Retirado do artigo Miller et al. (2019). Distance sampling in R. Journal of Statistical Sofware 89(1)

# instalar pacotes necessários
#install.packages("Distance")

# instalar pacotes adicionais
#install.packages("mrds")
#install.packages("dsm")
#install.packages("mads")
#install.packages("dsims")

# carregar pacotes 
library(Distance)
Carregando pacotes exigidos: mrds
This is mrds 2.2.8
Built: R 4.3.0; ; 2023-04-28 17:39:52 UTC; unix

Attaching package: ‘Distance’

The following object is masked from ‘package:mrds’:

    create.bins
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(DT)
library(flextable)
library(ggplot2)
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library(plotly)

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following objects are masked from ‘package:flextable’:

    highlight, style

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(readr)
library(readxl)
library(stringr)
library(tibble)
library(tidyr)

# carregar as funções da pasta R
# carregar função script_carregar_funções_pasta_r.R
source(
  paste0(
    here::here(),
    "/R/minhas_funcoes.R"
  )
)

Attaching package: ‘ggpubr’

The following objects are masked from ‘package:flextable’:

    border, font, rotate

here() starts at /home/usuario/Documentos/Vitor/Piper3D/WWF/Monitora/Dados/Monitora/Monitora/piper3d_monitora_florestal

Attaching package: ‘purrr’

The following object is masked from ‘package:flextable’:

    compose
# carregar dados
cutia_tap_arap <- transformar_para_distanceR_covariaveis() |> 
  filter(
    Region.Label == "Resex Tapajos-Arapiuns",
    sp_name == "Dasyprocta croconota"
  ) |> 
  drop_na(distance)
  
# readr::write_excel_csv(
#   cutia_tap_arap,
#   paste0(
#     here::here(),
#     "/data/cutia_tap_arap.csv"
#   ),
# )

cutia_tap_arap <- cutia_tap_arap |> 
  select(
    Region.Label,
    Area,
    Sample.Label,
    Effort,
    distance
  ) 

cutia_tap_arap |> 
  DT::datatable(filter = "top")
dados_completos |> 
  group_by(
    uc_name,
    ea_name
  ) |> 
  filter(day_effort == max(day_effort))  |> 
  drop_na(distance) |> 
  ungroup()
dados_completos |> 
  filter(
    uc_name == "Resex Tapajos-Arapiuns",
    sp_name == "Dasyprocta croconota"
  ) |> 
  datatable(filter = list(position = "top"))

Formatação do conjunto de dados

Variáveis necessárias para o data.frame:

Transectos que foram amostrados, mas que não tiveram observações (n = 0) devem ser incluídos no conjunto de dados com NA nas observações de distância e qualquer outra covariael para a qual não se tenha observação.

# cutia_tap_arap |> 
#   complete(Region.Label, Sample.Label, sp_name) |> 
#   datatable(filter = list(position = "top"))

Jogar a imputacao de NAs pra dentro da funcao carregar dados completos.

Determinando a distância para truncar os dados

# desenha o grafico com a distribuicao de distancias perpendiculares
cutia_tap_arap |> 
  filter(distance >= 1,
         distance <= 14) |> 
  plotar_distribuicao_distancia_interativo()
summary(cutia_tap_arap$distance)

Ajustando funções de detecção no R

Cutias da Resex Tapajós-Arapiuns para diferentes distâncias de truncamento

Half-Normal sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Half-normal como key function usando o argumento key, sem termo de ajuste.


cutia_tap_arap_filtrado <- cutia_tap_arap |> 
  filter(distance >= 1,
         distance <= 14)

# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# dsitancias de truncamento
dist_truncamento <- list(
  `14 metros` = 14, 
  `12 metros` = 12, 
  `10 metros` = 10,
  `7 metros` = 7
)

# Key function - Half-normal 
cutia_tap_arap_hn <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_hn(
    cutia_tap_arap_filtrado, 
    truncamento = .x
  )
  )
cutia_tap_arap_hn

Hazard-Rate sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados da cutia Dasyprocta croconota, configurando uma distância limite de 20m e usando Hazard rate como key function usando o argumento key.

# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# Key function - Hazard-rate
cutia_tap_arap_hr <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_hr(
    cutia_tap_arap_filtrado, 
    truncamento = .x
  )
  )

Uniform sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Uniform como key function usando o argumento key, sem termo de ajuste.

# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# Key function - Uniform
cutia_tap_arap_unif <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_unif(
    cutia_tap_arap, 
    truncamento = .x
  )
)
Seleção de modelos
summarize_ds_models(
  cutia_tap_arap_hn$`14 metros`$`Sem termo`,
cutia_tap_arap_hn$`14 metros`$Cosseno,
  cutia_tap_arap_hn$`14 metros`$`Hermite polinomial`,
cutia_tap_arap_hr$`14 metros`$`Sem termo`,
cutia_tap_arap_hr$`14 metros`$Cosseno,
cutia_tap_arap_hr$`14 metros`$`Polinomial simples`,
cutia_tap_arap_unif$`14 metros`$Cosseno,
cutia_tap_arap_unif$`14 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_tap_arap_hn$`12 metros`$`Sem termo`,
cutia_tap_arap_hn$`12 metros`$Cosseno,
  cutia_tap_arap_hn$`12 metros`$`Hermite polinomial`,
cutia_tap_arap_hr$`12 metros`$`Sem termo`,
cutia_tap_arap_hr$`12 metros`$Cosseno,
cutia_tap_arap_hr$`12 metros`$`Polinomial simples`,
cutia_tap_arap_unif$`12 metros`$Cosseno,
cutia_tap_arap_unif$`12 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_tap_arap_hn$`10 metros`$`Sem termo`,
cutia_tap_arap_hn$`10 metros`$Cosseno,
  cutia_tap_arap_hn$`10 metros`$`Hermite polinomial`,
cutia_tap_arap_hr$`10 metros`$`Sem termo`,
cutia_tap_arap_hr$`10 metros`$Cosseno,
cutia_tap_arap_hr$`10 metros`$`Polinomial simples`,
cutia_tap_arap_unif$`10 metros`$Cosseno,
cutia_tap_arap_unif$`10 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_tap_arap_hn$`7 metros`$`Sem termo`,
cutia_tap_arap_hn$`7 metros`$Cosseno,
  cutia_tap_arap_hn$`7 metros`$`Hermite polinomial`,
cutia_tap_arap_hr$`7 metros`$`Sem termo`,
cutia_tap_arap_hr$`7 metros`$Cosseno,
cutia_tap_arap_hr$`7 metros`$`Polinomial simples`,
cutia_tap_arap_unif$`7 metros`$Cosseno,
cutia_tap_arap_unif$`7 metros`$`Polinomial simples`
)

Resumir o resultado dos modelos

O que tem que ter?

Os gráficos (probabilidade de detecção pela distância, com a curva ajustada, exemplo abaixo, fazer no ggplot), resultado do goodness of fit (gof_ds()), cada modelo vai ter que ter um nome diferente numa tabela(?)

plot(cutia_tap_arap_hn, breaks = seq(0, 20, 2.5))
plot(cutia_tap_arap_hn_herm, breaks = seq(0, 20, 2.5))
plot(cutia_tap_arap_hn_cos, breaks = seq(0, 20, 2.5))
plot(cutia_tap_arap_hr, breaks = seq(0, 20, 2.5))
plot(cutia_tap_arap_hr_poly, breaks = seq(0, 20, 2.5))
plot(cutia_tap_arap_hr_cos, breaks = seq(0, 20, 2.5))

Checagem e seleção de modelos

Podemos usar a função summary para obter informações importantes sobre o modelo.


lista_modelos <- list(
  cutia_tap_arap_hn,
  cutia_tap_arap_hn_herm,
  cutia_tap_arap_hn_cos,
  cutia_tap_arap_hr,
  cutia_tap_arap_hr_poly,
  cutia_tap_arap_hr_cos
)

purrr::map(lista_modelos, \(x) summary(x))
summarize_ds_models(
  cutia_tap_arap_hn,
  cutia_tap_arap_hn_herm,
  cutia_tap_arap_hn_cos,
  cutia_tap_arap_hr,
  cutia_tap_arap_hr_poly,
  cutia_tap_arap_hr_cos
)

O resultado inclui detalhes sobre o dado e a especificação do modelo, assim como dos coeficientes (\(\beta_{j}\)) e sua inceteza, a média do valor de detectabilidade e sua incerteza e uma estimativa da abundância na área coberta pela amostragem (sem levar em consideração o tamanho dos agrupamentos, ou bandos).

Bondade de ajuste

Para visualizar quão bem a função de detecção se ajusta aos dados quanto temos as distâncias exatas podemos usar um plot de quantis empíricos x teóricos (Q-Q plot). Ele compara a função de distribuição cumulativa (CDF) dos valores ajustados da função detecção a distribuição empírica dos dados (EDF).

Também podemos usar o teste de Cramér-von Mises para testar se os pontos da EDF e da CDF tem origem na mesma distribuição. O teste usa a soma de todas as distâncias entre um ponto e a linha y = x para formar a estatística a ser testada. Um resultado significativo fornece evidência contra a hiipótese nula, sugerindo que o modelo não se ajusta bem aos dados.

# ajustando um modelo Half-normal
cutia_hn <- ds(data = cutia_tap_arap_15,
                 truncation = 20,
                 transect = "line",
                 key = "hn", 
                 adjustment = NULL)

# conduzindo o teste dfe bondadede ajuste de Cramer-von Mises
gof_ds(cutia_hn)

gof_ds(cutia_hr_time)

O resutlado do teste aponta que o modelo Half-normal deve ser descartado.

Testes de bondade de ajuste de chi-quadrado são gerados usando a função gof_ds quando as distâncias forneceidas estão categorizadas.

Seleção de Modelos

Uma vez que temos um conjunto de modelos plausíveis, podemos utilizar o cirtériode informaçãode Akaike (AIC) para selecionar entre os modelos o que melhor se ajusta aos dados utilizando a função summarize_ds_models.

# gerando uma tabela de seleção de modelos usando AIC
summarize_ds_models(cutia_hn, cutia_hr_time, cutia_hr_time_size)

O melhor modelo é o Hazard-rate com tempo de senso e tamanho do grupo como covariáveis.

Estimando a abundância e a variância

Estimando abundância e variância no R

Para obter a abundância na região de estudo, primeiro calculamos a abundância na área amostrada para obter \(N_c\) e em seguida escalonamos esse valor para toda a área de estudo multiplicando \(N_c\) pela razão entre a área amostrada e a área da região. Para estimar a abundância na área amostrada, utilizamos as estimativas de probabilidade de detecção no estimador de Horvitz-Thompson.

Quando fornecemos os dados no formato correto (“flatfile”) ds irá automaticamente calcular as estimativas de abundância baseado nas informações de amostragem presenta nos dados.

summary(cutia_hn)
  1. Summary statistics: fornece as áreas, aŕea de amostragem, esforço, número de observações, número de transectos, taxa de encontro, seus erros padrões e coeficientes de variação para cada estrato;

  2. Abundance: fornece estimativas, erros padrões, coeficientesde variação, intervalos de confiança inferior e superior, graus de liberdade para a estimativa de abundância de cada estrato;

  3. Densidade: lista as mesmas estatísticas de Abundance, só que para densidade.

Funções Exploratórias Adicionais

contar_n_repeticoes_trilha() - conta o número de vezes que cada trilha foi visitada

Adicionando covariavel

Ajuste Hermite pollynomial usa od código "herm" e polinomial simples "poly".

Podemos incluir covariáveis utilizando o argumento formula = ~ .... Abaixo, está especificado um modelo “Hazard-rate” para os dados de cutia q ue inclui o tempo de senso como covariável e uma distância limite de 20m.

cutia_hr_time <- cutia_tap_arap_15 |> 
  ds(truncation = 20,
     key = "hr",
     formula = ~ cense_time)

Adicionando uma segunda covariável: tamanho do grupo.

cutia_hr_time_size <- ds(data = cutia_tap_arap_15,
                     truncation = 20,
                     transect = "line",
                     key = "hr",
                     formula = ~ cense_time + size)
plot(cutia_hr_time)
plot(cutia_hr_time_size)

Cutias da ESEC Terra do Meio para diferentes distâncias de truncamento

cutia_esec_terra_meio <- transformar_para_distanceR_covariaveis() |> 
  filter(
    Region.Label == "Esec da Terra do Meio",
    sp_name == "Dasyprocta croconota"
  ) |> 
  drop_na(distance)
  
# desenha o grafico com a distribuicao de distancias perpendiculares
cutia_esec_terra_meio |> 
  filter(distance >= 1,
         distance < 15) |> 
  plotar_distribuicao_distancia_interativo(largura_caixa = 1)

Half-Normal sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Half-normal como key function usando o argumento key, sem termo de ajuste.

cutia_esec_terra_meio_filtrado
cutia_esec_terra_meio_filtrado <- cutia_esec_terra_meio |> 
  filter(distance >= 1,
         distance < 15)
# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# dsitancias de truncamento
dist_truncamento <- list(
  #`20 metros` = 20, 
  `15 metros` = 15, 
  `12 metros` = 12,
  `10 metros` = 10
)

# Key function - Half-normal 
cutia_esec_terra_meio_hn <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_hn(
    cutia_esec_terra_meio_filtrado, 
    truncamento = .x
  )
  )
cutia_esec_terra_meio_hn

Hazard-Rate sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados da cutia Dasyprocta croconota, configurando uma distância limite de 20m e usando Hazard rate como key function usando o argumento key.

# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# Key function - Hazard-rate
cutia_esec_terra_meio_hr <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_hr(
    cutia_esec_terra_meio_filtrado, 
    truncamento = .x
  )
  )

Uniform sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Uniform como key function usando o argumento key, sem termo de ajuste.

# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# Key function - Uniform
cutia_esec_terra_meio_unif <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_unif(
    cutia_tap_arap, 
    truncamento = .x
  )
  )
Seleção de modelos
summarize_ds_models(
  cutia_esec_terra_meio_hn$`20 metros`$`Sem termo`,
cutia_esec_terra_meio_hn$`20 metros`$Cosseno,
  cutia_esec_terra_meio_hn$`20 metros`$`Hermite polinomial`,
cutia_esec_terra_meio_hr$`20 metros`$`Sem termo`,
cutia_esec_terra_meio_hr$`20 metros`$Cosseno,
cutia_esec_terra_meio_hr$`20 metros`$`Polinomial simples`,
cutia_esec_terra_meio_unif$`20 metros`$Cosseno,
cutia_esec_terra_meio_unif$`20 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_esec_terra_meio_hn$`15 metros`$`Sem termo`,
cutia_esec_terra_meio_hn$`15 metros`$Cosseno,
  cutia_esec_terra_meio_hn$`15 metros`$`Hermite polinomial`,
cutia_esec_terra_meio_hr$`15 metros`$`Sem termo`,
cutia_esec_terra_meio_hr$`15 metros`$Cosseno,
cutia_esec_terra_meio_hr$`15 metros`$`Polinomial simples`,
cutia_esec_terra_meio_unif$`15 metros`$Cosseno,
cutia_esec_terra_meio_unif$`15 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_esec_terra_meio_hn$`10 metros`$`Sem termo`,
cutia_esec_terra_meio_hn$`10 metros`$Cosseno,
  cutia_esec_terra_meio_hn$`10 metros`$`Hermite polinomial`,
cutia_esec_terra_meio_hr$`10 metros`$`Sem termo`,
cutia_esec_terra_meio_hr$`10 metros`$Cosseno,
cutia_esec_terra_meio_hr$`10 metros`$`Polinomial simples`,
cutia_esec_terra_meio_unif$`10 metros`$Cosseno,
cutia_esec_terra_meio_unif$`10 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_esec_terra_meio_hn$`12 metros`$`Sem termo`,
cutia_esec_terra_meio_hn$`12 metros`$Cosseno,
  cutia_esec_terra_meio_hn$`12 metros`$`Hermite polinomial`,
cutia_esec_terra_meio_hr$`12 metros`$`Sem termo`,
cutia_esec_terra_meio_hr$`12 metros`$Cosseno,
cutia_esec_terra_meio_hr$`12 metros`$`Polinomial simples`,
cutia_esec_terra_meio_unif$`12 metros`$Cosseno,
cutia_esec_terra_meio_unif$`12 metros`$`Polinomial simples`
)

Cutias da Parna da Serra do Pardo para diferentes distâncias de truncamento

cutia_parna_serra_pardo <- transformar_para_distanceR_covariaveis() |> 
  filter(
    Region.Label == "Parna da Serra do Pardo",
    sp_name == "Dasyprocta croconota"
  ) |> 
  drop_na(distance)
  
# desenha o grafico com a distribuicao de distancias perpendiculares
cutia_parna_serra_pardo |> 
  filter(distance < 15,
         distance > 0) |> 
  plotar_distribuicao_distancia_interativo()

Half-Normal sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Half-normal como key function usando o argumento key, sem termo de ajuste.

# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# dsitancias de truncamento
dist_truncamento <- list(
  `20 metros` = 20, 
  `15 metros` = 15, 
  `10 metros` = 10,
  `5 metros` = 5
)

# Key function - Half-normal 
cutia_parna_serra_pardo_hn <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_hn(
    cutia_parna_serra_pardo, 
    truncamento = .x
  )
  )
cutia_parna_serra_pardo_hn

Hazard-Rate sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados da cutia Dasyprocta croconota, configurando uma distância limite de 20m e usando Hazard rate como key function usando o argumento key.

# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# Key function - Hazard-rate
cutia_parna_serra_pardo_hr <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_hr(
    cutia_parna_serra_pardo, 
    truncamento = .x
  )
  )

Uniform sem termos de ajuste e com termos de ajuste Cosseno e Polinomial de Hermite

Ajustando um modelo ao dados das cutias Dasyprocta croconota, configurando uma distância limite de 20m e usando Uniform como key function usando o argumento key, sem termo de ajuste.

# ajustando a função de detecção para uma distancia de truncamento de 20, 15, 10 e 5 metros
# Key function - Uniform
cutia_parna_serra_pardo_unif <- purrr::map(
  dist_truncamento,
  \(.x) ajuste_modelos_distance_unif(
    cutia_parna_serra_pardo, 
    truncamento = .x
  )
)
Seleção de modelos
summarize_ds_models(
  cutia_parna_serra_pardo_hn$`20 metros`$`Sem termo`,
cutia_parna_serra_pardo_hn$`20 metros`$Cosseno,
  cutia_parna_serra_pardo_hn$`20 metros`$`Hermite polinomial`,
cutia_parna_serra_pardo_hr$`20 metros`$`Sem termo`,
cutia_parna_serra_pardo_hr$`20 metros`$Cosseno,
cutia_parna_serra_pardo_hr$`20 metros`$`Polinomial simples`,
cutia_parna_serra_pardo_unif$`20 metros`$Cosseno,
cutia_parna_serra_pardo_unif$`20 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_parna_serra_pardo_hn$`15 metros`$`Sem termo`,
cutia_parna_serra_pardo_hn$`15 metros`$Cosseno,
  cutia_parna_serra_pardo_hn$`15 metros`$`Hermite polinomial`,
cutia_parna_serra_pardo_hr$`15 metros`$`Sem termo`,
cutia_parna_serra_pardo_hr$`15 metros`$Cosseno,
cutia_parna_serra_pardo_hr$`15 metros`$`Polinomial simples`,
cutia_parna_serra_pardo_unif$`15 metros`$Cosseno,
cutia_parna_serra_pardo_unif$`15 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_parna_serra_pardo_hn$`10 metros`$`Sem termo`,
cutia_parna_serra_pardo_hn$`10 metros`$Cosseno,
  cutia_parna_serra_pardo_hn$`10 metros`$`Hermite polinomial`,
cutia_parna_serra_pardo_hr$`10 metros`$`Sem termo`,
cutia_parna_serra_pardo_hr$`10 metros`$Cosseno,
cutia_parna_serra_pardo_hr$`10 metros`$`Polinomial simples`,
cutia_parna_serra_pardo_unif$`10 metros`$`Sem termo`,
cutia_parna_serra_pardo_unif$`10 metros`$Cosseno,
cutia_parna_serra_pardo_unif$`10 metros`$`Polinomial simples`
)
summarize_ds_models(
  cutia_parna_serra_pardo_hn$`5 metros`$`Sem termo`,
cutia_parna_serra_pardo_hn$`5 metros`$Cosseno,
  cutia_parna_serra_pardo_hn$`5 metros`$`Hermite polinomial`,
cutia_parna_serra_pardo_hr$`5 metros`$`Sem termo`,
cutia_parna_serra_pardo_hr$`5 metros`$Cosseno,
cutia_parna_serra_pardo_hr$`5 metros`$`Polinomial simples`,
cutia_parna_serra_pardo_unif$`5 metros`$`Sem termo`,
cutia_parna_serra_pardo_unif$`5 metros`$Cosseno,
cutia_parna_serra_pardo_unif$`5 metros`$`Polinomial simples`
)
Tentativa de fazer a seleçã ode modelos usando purrr - tentar aninhar mais um map
purrr::map_df(
  list(
    cutia_esec_terra_meio_hn$`20 metros`,
    cutia_esec_terra_meio_hr$`20 metros`
  ),
  \(.x) purrr::map_df(.x, \(.y) summarize_ds_models(.y))
)

purrr::map_df(
  cutia_esec_terra_meio_hn$`15 metros`,
  \(.x) summarize_ds_models(.x)
)

purrr::map_df(
  cutia_esec_terra_meio_hn$`10 metros`,
  \(.x) summarize_ds_models(.x)
)

purrr::map_df(
  cutia_esec_terra_meio_hn$`5 metros`,
  \(.x) summarize_ds_models(.x)
)

Primeira espécie para dados com repetição

Saguinus midas no Parna Montanhas do Tumucumaque

Fonte: datuopinion.com

Carregar dados

sagui_mont_tumuc <- transformar_para_distanceR_covariaveis() |> 
  filter(
    Region.Label == "Parna Montanhas do Tumucumaque",
    sp_name == "Saguinus midas"
  ) |> 
  drop_na(distance)

Distribuição das distâncias perpendiculares

sagui_mont_tumuc |> 
  plotar_distribuicao_distancia_interativo()

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 10

sagui_mont_tumuc_hn <- sagui_mont_tumuc |> 
  ajuste_modelos_distance_hn(lista_termos_ajuste = truncamento = 10)

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 10

sagui_mont_tumuc_hr <- sagui_mont_tumuc |> 
  ajuste_modelos_distance_hr(truncamento = 10)

Plot dos modelos

sagui_mont_tumuc_hn |> 
  purrr::map(\(.x) plot(.x)) 
sagui_mont_tumuc_hr |> 
  purrr::map(\(.x) plot(.x)) 

Seleção de modelos

summarize_ds_models(
  sagui_mont_tumuc_hn$`Sem termo`,
  sagui_mont_tumuc_hn$Cosseno,
  sagui_mont_tumuc_hn$`Hermite polinomial`,
  sagui_mont_tumuc_hr$`Sem termo`,
  sagui_mont_tumuc_hr$Cosseno,
  sagui_mont_tumuc_hr$`Polinomial simples`
)

Teste de bondade de ajuste

sagui_mont_tumuc_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))
sagui_mont_tumuc_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
sagui_mont_tumuc_hn$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
sagui_mont_tumuc_hn$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
sagui_mont_tumuc_hn$`Sem termo`$dht$individuals$D
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
sagui_mont_tumuc_hr$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
sagui_mont_tumuc_hr$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
sagui_mont_tumuc_hr$`Sem termo`$dht$individuals$D

Segunda espécie para dados com repetição

Myoprocta pratti na Resex Alto Tarauacá

Fonte: zoochat.com

Carregar dados

cutia_alto_tarau <- transformar_para_distanceR_covariaveis() |> 
  filter(
    Region.Label == "Resex Alto Tarauacá",
    sp_name == "Myoprocta pratti"
  ) |> 
  drop_na(distance)

Distribuição das distâncias perpendiculares

cutia_alto_tarau |> 
  plotar_distribuicao_distancia_interativo()

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 10

cutia_alto_tarau_hn <- cutia_alto_tarau |> 
  ajuste_modelos_distance_hn(truncamento = 10)

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 10

cutia_alto_tarau_hr <- cutia_alto_tarau |> 
  ajuste_modelos_distance_hr(truncamento = 10)

Plot dos modelos

cutia_alto_tarau_hn |> 
  purrr::map(\(.x) plot(.x)) 
cutia_alto_tarau_hr |> 
  purrr::map(\(.x) plot(.x)) 

Seleção de modelos

summarize_ds_models(
  cutia_alto_tarau_hn$`Sem termo`,
  cutia_alto_tarau_hn$Cosseno,
  cutia_alto_tarau_hn$`Hermite polinomial`,
  cutia_alto_tarau_hr$`Sem termo`,
  cutia_alto_tarau_hr$Cosseno,
  cutia_alto_tarau_hr$`Polinomial simples`
)

Teste de bondade de ajuste

cutia_alto_tarau_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))
cutia_alto_tarau_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
cutia_alto_tarau_hn$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
cutia_alto_tarau_hn$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
cutia_alto_tarau_hn$`Sem termo`$dht$individuals$D
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
cutia_alto_tarau_hr$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
cutia_alto_tarau_hr$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
cutia_alto_tarau_hr$`Sem termo`$dht$individuals$D

Terceira espécie para dados com repetição

Lagothrix cana na Rebio do Jaru

Fonte: zoochat.com

Carregar dados

macaco_jaru <- transformar_para_distanceR_covariaveis() |> 
  filter(
    Region.Label == "Rebio do Jaru",
    sp_name == "Lagothrix cana"
  ) |> 
  drop_na(distance)

Distribuição das distâncias perpendiculares

macaco_jaru |> 
  plotar_distribuicao_distancia_interativo()

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 20

macaco_jaru_hn <- macaco_jaru |> 
  ajuste_modelos_distance_hn(truncamento = 20)

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 20

macaco_jaru_hr <- macaco_jaru |> 
  ajuste_modelos_distance_hr(truncamento = 20)

Plot dos modelos

macaco_jaru_hn |> 
  purrr::map(\(.x) plot(.x)) 
macaco_jaru_hr |> 
  purrr::map(\(.x) plot(.x)) 

Seleção de modelos

summarize_ds_models(
  macaco_jaru_hn$`Sem termo`,
  macaco_jaru_hn$Cosseno,
  macaco_jaru_hn$`Hermite polinomial`,
  macaco_jaru_hr$`Sem termo`,
  macaco_jaru_hr$Cosseno,
  macaco_jaru_hr$`Polinomial simples`
)

Teste de bondade de ajuste

macaco_jaru_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))
macaco_jaru_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
macaco_jaru_hn$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
macaco_jaru_hn$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
macaco_jaru_hn$`Sem termo`$dht$individuals$D
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
macaco_jaru_hr$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
macaco_jaru_hr$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
macaco_jaru_hr$`Sem termo`$dht$individuals$D

Quarta espécie para dados com repetição

Mazama americana na Resex Tapajos-Arapiuns

Fonte: zoochat.com

Carregar dados

cervo_tap_arap <- transformar_para_distanceR_covariaveis() |> 
  filter(
    Region.Label == "Resex Tapajos-Arapiuns",
    sp_name == "Mazama americana"
  ) |> 
  drop_na(distance)

Distribuição das distâncias perpendiculares

cervo_tap_arap |> 
  plotar_distribuicao_distancia_interativo()

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 13

cervo_tap_arap_hn <- cervo_tap_arap |> 
  ajuste_modelos_distance_hn(truncamento = 13)

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 13

cervo_tap_arap_hr <- cervo_tap_arap |> 
  ajuste_modelos_distance_hr(truncamento = 13)

Plot dos modelos

cervo_tap_arap_hn |> 
  purrr::map(\(.x) plot(.x)) 
cervo_tap_arap_hr |> 
  purrr::map(\(.x) plot(.x)) 

Seleção de modelos

summarize_ds_models(
  cervo_tap_arap_hn$`Sem termo`,
  cervo_tap_arap_hn$Cosseno,
  cervo_tap_arap_hn$`Hermite polinomial`,
  cervo_tap_arap_hr$`Sem termo`,
  cervo_tap_arap_hr$Cosseno,
  cervo_tap_arap_hr$`Polinomial simples`
)

Teste de bondade de ajuste

cervo_tap_arap_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))
cervo_tap_arap_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
cervo_tap_arap_hn$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
cervo_tap_arap_hn$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
cervo_tap_arap_hn$`Sem termo`$dht$individuals$D
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
cervo_tap_arap_hr$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
cervo_tap_arap_hr$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
cervo_tap_arap_hr$`Sem termo`$dht$individuals$D

Quinta espécie para dados com repetição

Tinamus major na Parna Montanhas do Tumucumaque

Fonte: pinterest.com

Carregar dados

inambu_mont_tumuc <- transformar_para_distanceR_covariaveis() |> 
  filter(
    Region.Label == "Parna Montanhas do Tumucumaque",
    sp_name == "Tinamus major"
  ) |> 
  drop_na(distance)

Distribuição das distâncias perpendiculares

inambu_mont_tumuc |> 
  plotar_distribuicao_distancia_interativo()

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 15

inambu_mont_tumuc_hn <- inambu_mont_tumuc |> 
  ajuste_modelos_distance_hn(truncamento = 15)

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 15

inambu_mont_tumuc_hr <- inambu_mont_tumuc |> 
  ajuste_modelos_distance_hr(truncamento = 15)

Plot dos modelos

inambu_mont_tumuc_hn |> 
  purrr::map(\(.x) plot(.x)) 
inambu_mont_tumuc_hr |> 
  purrr::map(\(.x) plot(.x)) 

Seleção de modelos

summarize_ds_models(
  inambu_mont_tumuc_hn$`Sem termo`,
  inambu_mont_tumuc_hn$Cosseno,
  inambu_mont_tumuc_hn$`Hermite polinomial`,
  inambu_mont_tumuc_hr$`Sem termo`,
  inambu_mont_tumuc_hr$Cosseno,
  inambu_mont_tumuc_hr$`Polinomial simples`
)

Teste de bondade de ajuste

inambu_mont_tumuc_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))
inambu_mont_tumuc_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
inambu_mont_tumuc_hn$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
inambu_mont_tumuc_hn$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
inambu_mont_tumuc_hn$`Sem termo`$dht$individuals$D
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
inambu_mont_tumuc_hr$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
inambu_mont_tumuc_hr$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
inambu_mont_tumuc_hr$`Sem termo`$dht$individuals$D

Tetnativa de filtragem e seleção de dados para eliminar repetições

Na primeira tentativa de ajuste do modelo distance para dados sem repetição, os dados da cutia Dasyprocta croconota, sem estratificação, para o Parna da Serra do Pardo, Esec da Terra do Meio e Resex Riozinho do Anfrísio. Em seguida, os dados da mesma espécie serão analisados para Resex Tapajós-Arapiuns estratificados por ano.

Dasyprocta croconota na Parna da Serra do Pardo

Fonte: biolib.cz

Carregar dados

dasy_croc_serra_pardo <- transformar_para_distanceR_covariaveis_sem_repeticao() |> 
  filter(
    Region.Label == "Parna da Serra do Pardo", 
    sp_name == "Dasyprocta croconota"
  ) |> 
  drop_na(distance)

dasy_croc_serra_pardo

Verificar o número de observações por data de amostragem

teste1 <- dasy_croc_serra_pardo |> 
  group_by(Sample.Label, sampling_day, year, season) |> 
  count(sampling_day) |> 
  ungroup() |> 
  arrange(Sample.Label, sampling_day)

teste1

Verificar as datas com maior número de observações em cada ano

tentar gerar uma nova coluna usando uma condicional que repita uma única data para datas que ocorrem dentro do intervalo amostral. depois basta manter as observações únicas usando distinct()

teste2 <- dasy_croc_serra_pardo |> 
  group_by(Sample.Label, year, season) |> 
  count(sampling_day) |> 
  reframe(n_max = max(n)) |> 
  ungroup() |> 
  arrange(year)

teste2

Juntar as duas data.frames para obter as datas com maior número de observação em cada ano e excluir datas de amostragem repitidas na mesma estação e ano

dados_para_filtrar_por_data_quase_sem_repeticao <- teste1 |> 
  semi_join(
    teste2, 
    join_by(Sample.Label, year, season, n == n_max),
  ) |> 
  arrange(sampling_day) |>
  distinct(sampling_day, year, season)

dados_para_filtrar_por_data_quase_sem_repeticao

Distribuição das distâncias perpendiculares

dasy_croc_serra_pardo_quase_sem_repeticao |> 
  plotar_distribuicao_distancia_interativo(largura_caixa = 1)
Warning: Continuous y aesthetic
ℹ did you forget `aes(group = ...)`?

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 11

dasy_croc_serra_pardo_quase_sem_repeticao_hn <- dasy_croc_serra_pardo_quase_sem_repeticao |> 
  ajuste_modelos_distance_hn(truncamento = 11)
Fitting half-normal key function
AIC= 531.611
Starting AIC adjustment term selection.
Fitting half-normal key function
AIC= 531.611
Fitting half-normal key function with cosine(2) adjustments
AIC= 529.261
Fitting half-normal key function with cosine(2,3) adjustments
AIC= 537.772

Half-normal key function with cosine(2) adjustments selected.
Starting AIC adjustment term selection.
Fitting half-normal key function
AIC= 531.611
Fitting half-normal key function with Hermite(4) adjustments
AIC= 533.535

Half-normal key function selected.

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 11

dasy_croc_serra_pardo_quase_sem_repeticao_hr <- dasy_croc_serra_pardo_quase_sem_repeticao |> 
  ajuste_modelos_distance_hr(truncamento = 11)
Fitting hazard-rate key function
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).AIC= 532.634
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).Starting AIC adjustment term selection.
Fitting hazard-rate key function
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).AIC= 532.634
Fitting hazard-rate key function with cosine(2) adjustments
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).AIC= 534.644

Hazard-rate key function selected.
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).Starting AIC adjustment term selection.
Fitting hazard-rate key function
Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).AIC= 532.634
Fitting hazard-rate key function with simple polynomial(4) adjustments
Warning: Detection function is not strictly monotonic!AIC= 530.014
Fitting hazard-rate key function with simple polynomial(4,6) adjustments
Warning: Parameters or bounds appear to have different scalings.
  This can cause poor performance in optimization. 
  It is important for derivative free methods like BOBYQA, UOBYQA, NEWUOA.Warning: Estimated hazard-rate scale parameter close to 0 (on log scale). Possible problem in data (e.g., spike near zero distance).Warning: Model fitting did not converge. Try different initial values or different model
  Model failed to converge.

Hazard-rate key function with simple polynomial(4) adjustments selected.
Warning: Detection function is not strictly monotonic!

Plot dos modelos

dasy_croc_serra_pardo_quase_sem_repeticao_hn |> 
  purrr::map(\(.x) plot(.x)) 

$`Sem termo`
NULL

$Cosseno
NULL

$`Hermite polinomial`
NULL

dasy_croc_serra_pardo_quase_sem_repeticao_hr |> 
  purrr::map(\(.x) plot(.x)) 

$`Sem termo`
NULL

$Cosseno
NULL

$`Polinomial simples`
NULL

Seleção de modelos

summarize_ds_models(
  dasy_croc_serra_pardo_quase_sem_repeticao_hn$`Sem termo`,
  dasy_croc_serra_pardo_quase_sem_repeticao_hn$Cosseno,
  dasy_croc_serra_pardo_quase_sem_repeticao_hn$`Hermite polinomial`,
  dasy_croc_serra_pardo_quase_sem_repeticao_hr$`Sem termo`,
  dasy_croc_serra_pardo_quase_sem_repeticao_hr$Cosseno,
  dasy_croc_serra_pardo_quase_sem_repeticao_hr$`Polinomial simples`
)

Teste de bondade de ajuste

dasy_croc_serra_pardo_quase_sem_repeticao_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))

$`Sem termo`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 1.00771 p-value = 0.00236025

$Cosseno

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.97271 p-value = 0.00285138

$`Hermite polinomial`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 1.00771 p-value = 0.00236025

dasy_croc_serra_pardo_quase_sem_repeticao_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

$`Sem termo`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 1.07236 p-value = 0.0016668

$Cosseno

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 1.07236 p-value = 0.0016668

$`Polinomial simples`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 1.77766 p-value = 4.04921e-05

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
dasy_croc_serra_pardo_quase_sem_repeticao_hn$Cosseno$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
dasy_croc_serra_pardo_quase_sem_repeticao_hn$Cosseno$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
dasy_croc_serra_pardo_quase_sem_repeticao_hn$Cosseno$dht$individuals$D
NA
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
dasy_croc_serra_pardo_quase_sem_repeticao_hr$`Polinomial simples`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
dasy_croc_serra_pardo_quase_sem_repeticao_hr$`Polinomial simples`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
dasy_croc_serra_pardo_quase_sem_repeticao_hr$`Polinomial simples`$dht$individuals$D
NA

Dasyprocta croconota na Esec da Terra do Meio

Fonte: biolib.cz

Carregar dados

dasy_croc_terra_meio <- transformar_para_distanceR_covariaveis_sem_repeticao() |>   filter(
    Region.Label == "Esec da Terra do Meio", 
    sp_name == "Dasyprocta croconota"
  ) |> 
  drop_na(distance)

dasy_croc_terra_meio

Verificar o número de observações por data de amostragem

teste1 <- dasy_croc_terra_meio |> 
  group_by(Sample.Label, sampling_day, year, season) |> 
  count(sampling_day) |> 
  ungroup() |> 
  arrange(Sample.Label, sampling_day)

teste1

Verificar as datas com maior número de observações em cada ano

tentar gerar uma nova coluna usando uma condicional que repita uma única data para datas que ocorrem dentro do intervalo amostral. depois basta manter as observações únicas usando distinct()

teste2 <- dasy_croc_terra_meio |> 
  group_by(Sample.Label, year, season) |> 
  count(sampling_day) |> 
  reframe(n_max = max(n)) |> 
  ungroup() |> 
  arrange(year)

teste2

Juntar as duas data.frames para obter as datas com maior número de observação em cada ano e excluir datas de amostragem repitidas na mesma estação e ano

dados_para_filtrar_por_data_quase_sem_repeticao <- teste1 |> 
  semi_join(
    teste2, 
    join_by(Sample.Label, year, season, n == n_max),
  ) |> 
  arrange(sampling_day) |>
  distinct(sampling_day, year, season)

dados_para_filtrar_por_data_quase_sem_repeticao

Distribuição das distâncias perpendiculares

dasy_croc_terra_meio_quase_sem_repeticao |> 
  plotar_distribuicao_distancia_interativo(largura_caixa = 1)
Warning: Continuous y aesthetic
ℹ did you forget `aes(group = ...)`?

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 10

dasy_croc_terra_meio_quase_sem_repeticao_hn <- dasy_croc_terra_meio_quase_sem_repeticao |> 
  ajuste_modelos_distance_hn(truncamento = 10)
Fitting half-normal key function
AIC= 323.977
Starting AIC adjustment term selection.
Fitting half-normal key function
AIC= 323.977
Fitting half-normal key function with cosine(2) adjustments
Warning: Detection function is not strictly monotonic!AIC= 324.073

Half-normal key function selected.
Starting AIC adjustment term selection.
Fitting half-normal key function
AIC= 323.977
Fitting half-normal key function with Hermite(4) adjustments
AIC= 325.948

Half-normal key function selected.

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 10

dasy_croc_terra_meio_quase_sem_repeticao_hr <- dasy_croc_terra_meio_quase_sem_repeticao |> 
  ajuste_modelos_distance_hr(truncamento = 10)
Fitting hazard-rate key function
Warning: First partial hessian is singular; using second-partial hessian
AIC= 326.127
Starting AIC adjustment term selection.
Fitting hazard-rate key function
Warning: First partial hessian is singular; using second-partial hessian
AIC= 326.127
Fitting hazard-rate key function with cosine(2) adjustments
AIC= 326.399

Hazard-rate key function selected.
Starting AIC adjustment term selection.
Fitting hazard-rate key function
Warning: First partial hessian is singular; using second-partial hessian
AIC= 326.127
Fitting hazard-rate key function with simple polynomial(4) adjustments
AIC= 330.662

Hazard-rate key function selected.

Plot dos modelos

dasy_croc_terra_meio_quase_sem_repeticao_hn |> 
  purrr::map(\(.x) plot(.x)) 

$`Sem termo`
NULL

$Cosseno
NULL

$`Hermite polinomial`
NULL

dasy_croc_terra_meio_quase_sem_repeticao_hr |> 
  purrr::map(\(.x) plot(.x)) 

$`Sem termo`
NULL

$Cosseno
NULL

$`Polinomial simples`
NULL

Seleção de modelos

summarize_ds_models(
  dasy_croc_terra_meio_quase_sem_repeticao_hn$`Sem termo`,
  dasy_croc_terra_meio_quase_sem_repeticao_hn$Cosseno,
  dasy_croc_terra_meio_quase_sem_repeticao_hn$`Hermite polinomial`,
  dasy_croc_terra_meio_quase_sem_repeticao_hr$`Sem termo`,
  dasy_croc_terra_meio_quase_sem_repeticao_hr$Cosseno,
  dasy_croc_terra_meio_quase_sem_repeticao_hr$`Polinomial simples`
)

Teste de bondade de ajuste

dasy_croc_terra_meio_quase_sem_repeticao_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))

$`Sem termo`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.410198 p-value = 0.067913

$Cosseno

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.410198 p-value = 0.067913

$`Hermite polinomial`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.410198 p-value = 0.067913

dasy_croc_terra_meio_quase_sem_repeticao_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

$`Sem termo`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.452682 p-value = 0.0526422

$Cosseno

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.452682 p-value = 0.0526422

$`Polinomial simples`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.452682 p-value = 0.0526422

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
dasy_croc_terra_meio_quase_sem_repeticao_hn$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
dasy_croc_terra_meio_quase_sem_repeticao_hn$Cosseno$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade estimada, coeficiente de variação da densidade estimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
dasy_croc_terra_meio_quase_sem_repeticao_hn$Cosseno$dht$individuals$D
NA
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
dasy_croc_terra_meio_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
dasy_croc_terra_meio_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
dasy_croc_terra_meio_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$D
NA

Dasyprocta croconota na Resex Riozinho do Anfrísio

Fonte: biolib.cz

Carregar dados

dasy_croc_rio_anfr <- transformar_para_distanceR_covariaveis_sem_repeticao() |>   filter(
    Region.Label == "Resex Riozinho do Anfrísio", 
    sp_name == "Dasyprocta croconota"
  ) |> 
  drop_na(distance)

dasy_croc_rio_anfr

Verificar o número de observações por data de amostragem

teste1 <- dasy_croc_rio_anfr |> 
  group_by(Sample.Label, sampling_day, year, season) |> 
  count(sampling_day) |> 
  ungroup() |> 
  arrange(Sample.Label, sampling_day)

teste1

Verificar as datas com maior número de observações em cada ano

tentar gerar uma nova coluna usando uma condicional que repita uma única data para datas que ocorrem dentro do intervalo amostral. depois basta manter as observações únicas usando distinct()

teste2 <- dasy_croc_rio_anfr |> 
  group_by(Sample.Label, year, season) |> 
  count(sampling_day) |> 
  reframe(n_max = max(n)) |> 
  ungroup() |> 
  arrange(year)

teste2

Juntar as duas data.frames para obter as datas com maior número de observação em cada ano e excluir datas de amostragem repitidas na mesma estação e ano

dados_para_filtrar_por_data_quase_sem_repeticao <- teste1 |> 
  semi_join(
    teste2, 
    join_by(Sample.Label, year, season, n == n_max),
  ) |> 
  arrange(sampling_day) |>
  distinct(sampling_day, year, season)

dados_para_filtrar_por_data_quase_sem_repeticao

Distribuição das distâncias perpendiculares

filtro_datas_quase_sem_repeticao <- dados_para_filtrar_por_data_quase_sem_repeticao$sampling_day
  
dasy_croc_rio_anfr_quase_sem_repeticao <- dasy_croc_rio_anfr |> 
  filter(sampling_day %in% filtro_datas_quase_sem_repeticao,
         Region.Label == "Resex Riozinho do Anfrísio")

dasy_croc_rio_anfr_quase_sem_repeticao |> 
  plotar_distribuicao_distancia_interativo(largura_caixa = 1)
Warning: Continuous y aesthetic
ℹ did you forget `aes(group = ...)`?

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 11

dasy_croc_rio_anfr_quase_sem_repeticao_hn <- dasy_croc_rio_anfr_quase_sem_repeticao |> 
  ajuste_modelos_distance_hn(truncamento = 11)
Fitting half-normal key function
AIC= 256.177
Starting AIC adjustment term selection.
Fitting half-normal key function
AIC= 256.177
Fitting half-normal key function with cosine(2) adjustments
AIC= 258.16

Half-normal key function selected.
Starting AIC adjustment term selection.
Fitting half-normal key function
AIC= 256.177
Fitting half-normal key function with Hermite(4) adjustments
AIC= 258.177

Half-normal key function selected.

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 11

dasy_croc_rio_anfr_quase_sem_repeticao_hr <- dasy_croc_rio_anfr_quase_sem_repeticao |> 
  ajuste_modelos_distance_hr(truncamento = 11)
Fitting hazard-rate key function
Warning: First partial hessian is singular; using second-partial hessian
AIC= 257.999
Starting AIC adjustment term selection.
Fitting hazard-rate key function
Warning: First partial hessian is singular; using second-partial hessian
AIC= 257.999
Fitting hazard-rate key function with cosine(2) adjustments
AIC= 258.949

Hazard-rate key function selected.
Starting AIC adjustment term selection.
Fitting hazard-rate key function
Warning: First partial hessian is singular; using second-partial hessian
AIC= 257.999
Fitting hazard-rate key function with simple polynomial(4) adjustments
Warning: First partial hessian is singular; using second-partial hessian
AIC= 260.177

Hazard-rate key function selected.

Plot dos modelos

dasy_croc_rio_anfr_quase_sem_repeticao_hn |> 
  purrr::map(\(.x) plot(.x)) 

$`Sem termo`
NULL

$Cosseno
NULL

$`Hermite polinomial`
NULL

dasy_croc_rio_anfr_quase_sem_repeticao_hr |> 
  purrr::map(\(.x) plot(.x)) 

$`Sem termo`
NULL

$Cosseno
NULL

$`Polinomial simples`
NULL

Seleção de modelos

summarize_ds_models(
  dasy_croc_rio_anfr_quase_sem_repeticao_hn$`Sem termo`,
  dasy_croc_rio_anfr_quase_sem_repeticao_hn$Cosseno,
  dasy_croc_rio_anfr_quase_sem_repeticao_hn$`Hermite polinomial`,
  dasy_croc_rio_anfr_quase_sem_repeticao_hr$`Sem termo`,
  dasy_croc_rio_anfr_quase_sem_repeticao_hr$Cosseno,
  dasy_croc_rio_anfr_quase_sem_repeticao_hr$`Polinomial simples`
)

Teste de bondade de ajuste

dasy_croc_rio_anfr_quase_sem_repeticao_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))

$`Sem termo`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.585769 p-value = 0.0242743

$Cosseno

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.585769 p-value = 0.0242743

$`Hermite polinomial`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.585769 p-value = 0.0242743

dasy_croc_rio_anfr_quase_sem_repeticao_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

$`Sem termo`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.587752 p-value = 0.024001

$Cosseno

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.587752 p-value = 0.024001

$`Polinomial simples`

Goodness of fit results for ddf object

Distance sampling Cramer-von Mises test (unweighted)
Test statistic = 0.587752 p-value = 0.024001

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
dasy_croc_rio_anfr_quase_sem_repeticao_hn$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
dasy_croc_rio_anfr_quase_sem_repeticao_hn$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade estimada, coeficiente de variação da densidade estimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
dasy_croc_rio_anfr_quase_sem_repeticao_hn$`Sem termo`$dht$individuals$D
NA
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
dasy_croc_rio_anfr_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
dasy_croc_rio_anfr_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
dasy_croc_rio_anfr_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$D
NA

Dasyprocta croconota na Resex Tapajós Arapiuns - estratificado por ano

Fonte: biolib.cz

Carregar dados

dasy_croc_tap_arap <- transformar_para_distanceR_covariaveis_sem_repeticao() |>   filter(
    Region.Label == "Resex Tapajós Arapiuns", 
    sp_name == "Dasyprocta croconota"
  ) |> 
  drop_na(distance)

dasy_croc_tap_arap

Verificar o número de observações por data de amostragem

teste1 <- dasy_croc_tap_arap |> 
  group_by(Sample.Label, sampling_day, year, season) |> 
  count(sampling_day) |> 
  ungroup() |> 
  arrange(Sample.Label, sampling_day)

teste1

Verificar as datas com maior número de observações em cada ano

tentar gerar uma nova coluna usando uma condicional que repita uma única data para datas que ocorrem dentro do intervalo amostral. depois basta manter as observações únicas usando distinct()

teste2 <- dasy_croc_tap_arap |> 
  group_by(Sample.Label, year, season) |> 
  count(sampling_day) |> 
  reframe(n_max = max(n)) |> 
  ungroup() |> 
  arrange(year)

teste2

Juntar as duas data.frames para obter as datas com maior número de observação em cada ano e excluir datas de amostragem repitidas na mesma estação e ano

dados_para_filtrar_por_data_quase_sem_repeticao <- teste1 |> 
  semi_join(
    teste2, 
    join_by(Sample.Label, year, season, n == n_max),
  ) |> 
  arrange(sampling_day) |>
  distinct(sampling_day, year, season)

dados_para_filtrar_por_data_quase_sem_repeticao

Distribuição das distâncias perpendiculares

filtro_datas_quase_sem_repeticao <- dados_para_filtrar_por_data_quase_sem_repeticao$sampling_day
  
dasy_croc_tap_arap_quase_sem_repeticao <- dasy_croc_tap_arap |> 
  filter(sampling_day %in% filtro_datas_quase_sem_repeticao,
         Region.Label == "Resex Tapajós Arapiuns")

dasy_croc_tap_arap_quase_sem_repeticao |> 
  plotar_distribuicao_distancia_interativo(largura_caixa = 1)

Ajustando modelo distance com função de detecção Half-Normal e distancia de truncamento 11

dasy_croc_tap_arap_quase_sem_repeticao_hn <- dasy_croc_tap_arap_quase_sem_repeticao |> 
  ajuste_modelos_distance_hn(truncamento = 11)

Ajustando modelo distance com função de detecção Hazard-rate e distancia de truncamento 11

dasy_croc_tap_arap_quase_sem_repeticao_hr <- dasy_croc_tap_arap_quase_sem_repeticao |> 
  ajuste_modelos_distance_hr(truncamento = 11)

Plot dos modelos

dasy_croc_tap_arap_quase_sem_repeticao_hn |> 
  purrr::map(\(.x) plot(.x)) 
dasy_croc_tap_arap_quase_sem_repeticao_hr |> 
  purrr::map(\(.x) plot(.x)) 

Seleção de modelos

summarize_ds_models(
  dasy_croc_tap_arap_quase_sem_repeticao_hn$`Sem termo`,
  dasy_croc_tap_arap_quase_sem_repeticao_hn$Cosseno,
  dasy_croc_tap_arap_quase_sem_repeticao_hn$`Hermite polinomial`,
  dasy_croc_tap_arap_quase_sem_repeticao_hr$`Sem termo`,
  dasy_croc_tap_arap_quase_sem_repeticao_hr$Cosseno,
  dasy_croc_tap_arap_quase_sem_repeticao_hr$`Polinomial simples`
)

Teste de bondade de ajuste

dasy_croc_tap_arap_quase_sem_repeticao_hn |> 
  purrr::map(\(.x) gof_ds(model = .x))
dasy_croc_tap_arap_quase_sem_repeticao_hr |> 
  purrr::map(\(.x) gof_ds(model = .x))

Estimando a abundancia

# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
dasy_croc_tap_arap_quase_sem_repeticao_hn$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
dasy_croc_tap_arap_quase_sem_repeticao_hn$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade estimada, coeficiente de variação da densidade estimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
dasy_croc_tap_arap_quase_sem_repeticao_hn$`Sem termo`$dht$individuals$D
# área de estudo, tamanho da área de estudo, area coberta pelo esforço amostral, esforço amostral em metros, número de detecções, número de transectos (ea), taxa de encontro, coeficiente de variação da taxa de encontro  
dasy_croc_tap_arap_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$summary[1:9]
# área de estudo, tamanho da área de estudo, trilhas ou estações amostrais, esforço total em cada trilha, abundância estimada em cada estação amostral, número de detecções em cada estação amostral, área total amostrada
dasy_croc_tap_arap_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$Nhat.by.sample[1:8]
# total, densidade estimada, erro padrão da densidade destimada, coeficiente de variação da densidade destimada, intervalo de confiança inferior e superior do coeficiente de variação, gruas de liberdade
dasy_croc_tap_arap_quase_sem_repeticao_hr$`Sem termo`$dht$individuals$D
LS0tCnRpdGxlOiAiRGlzdGFuY2Ugbm8gUiBjb20gZGFkb3MgJ21vZGVsbyciCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClJldGlyYWRvIGRvIGFydGlnbyBNaWxsZXIgZXQgYWwuICgyMDE5KS4gRGlzdGFuY2Ugc2FtcGxpbmcgaW4gUi4gSm91cm5hbCBvZiBTdGF0aXN0aWNhbCBTb2Z3YXJlIDg5KDEpCgpgYGB7ciBzZXR1cH0KIyBpbnN0YWxhciBwYWNvdGVzIG5lY2Vzc8OhcmlvcwojaW5zdGFsbC5wYWNrYWdlcygiRGlzdGFuY2UiKQoKIyBpbnN0YWxhciBwYWNvdGVzIGFkaWNpb25haXMKI2luc3RhbGwucGFja2FnZXMoIm1yZHMiKQojaW5zdGFsbC5wYWNrYWdlcygiZHNtIikKI2luc3RhbGwucGFja2FnZXMoIm1hZHMiKQojaW5zdGFsbC5wYWNrYWdlcygiZHNpbXMiKQoKIyBjYXJyZWdhciBwYWNvdGVzIApsaWJyYXJ5KERpc3RhbmNlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KGZsZXh0YWJsZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHRpZHlyKQoKIyBjYXJyZWdhciBhcyBmdW7Dp8O1ZXMgZGEgcGFzdGEgUgojIGNhcnJlZ2FyIGZ1bsOnw6NvIHNjcmlwdF9jYXJyZWdhcl9mdW7Dp8O1ZXNfcGFzdGFfci5SCnNvdXJjZSgKICBwYXN0ZTAoCiAgICBoZXJlOjpoZXJlKCksCiAgICAiL1IvbWluaGFzX2Z1bmNvZXMuUiIKICApCikKCiMgY2FycmVnYXIgZGFkb3MKY3V0aWFfdGFwX2FyYXAgPC0gdHJhbnNmb3JtYXJfcGFyYV9kaXN0YW5jZVJfY292YXJpYXZlaXMoKSB8PiAKICBmaWx0ZXIoCiAgICBSZWdpb24uTGFiZWwgPT0gIlJlc2V4IFRhcGFqb3MtQXJhcGl1bnMiLAogICAgc3BfbmFtZSA9PSAiRGFzeXByb2N0YSBjcm9jb25vdGEiCiAgKSB8PiAKICBkcm9wX25hKGRpc3RhbmNlKQogIAojIHJlYWRyOjp3cml0ZV9leGNlbF9jc3YoCiMgICBjdXRpYV90YXBfYXJhcCwKIyAgIHBhc3RlMCgKIyAgICAgaGVyZTo6aGVyZSgpLAojICAgICAiL2RhdGEvY3V0aWFfdGFwX2FyYXAuY3N2IgojICAgKSwKIyApCgpjdXRpYV90YXBfYXJhcCA8LSBjdXRpYV90YXBfYXJhcCB8PiAKICBzZWxlY3QoCiAgICBSZWdpb24uTGFiZWwsCiAgICBBcmVhLAogICAgU2FtcGxlLkxhYmVsLAogICAgRWZmb3J0LAogICAgZGlzdGFuY2UKICApIAoKY3V0aWFfdGFwX2FyYXAgfD4gCiAgRFQ6OmRhdGF0YWJsZShmaWx0ZXIgPSAidG9wIikKYGBgCgpgYGB7cn0KZGFkb3NfY29tcGxldG9zIHw+IAogIGdyb3VwX2J5KAogICAgdWNfbmFtZSwKICAgIGVhX25hbWUKICApIHw+IAogIGZpbHRlcihkYXlfZWZmb3J0ID09IG1heChkYXlfZWZmb3J0KSkgIHw+IAogIGRyb3BfbmEoZGlzdGFuY2UpIHw+IAogIHVuZ3JvdXAoKQpgYGAKCmBgYHtyfQpkYWRvc19jb21wbGV0b3MgfD4gCiAgZmlsdGVyKAogICAgdWNfbmFtZSA9PSAiUmVzZXggVGFwYWpvcy1BcmFwaXVucyIsCiAgICBzcF9uYW1lID09ICJEYXN5cHJvY3RhIGNyb2Nvbm90YSIKICApIHw+IAogIGRhdGF0YWJsZShmaWx0ZXIgPSBsaXN0KHBvc2l0aW9uID0gInRvcCIpKQpgYGAKCiMgRm9ybWF0YcOnw6NvIGRvIGNvbmp1bnRvIGRlIGRhZG9zCgpWYXJpw6F2ZWlzIG5lY2Vzc8OhcmlhcyBwYXJhIG8gYGRhdGEuZnJhbWVgOgoKLSAgIGBSZWdpb24uTGFiZWxgOiB2ZXRvciBmYXRvciBjb20gbyBlc3RyYXRvIGNvbnRlbmRvIG8gdHJhbnNlY3RvIChwb2RlIHNlciB1bWEgZXN0cmF0aWZpY2HDp8OjbyBwcsOpLWFtb3N0cmFnZW0gLSBVQ3MgLSBvdSBww7NzLWFtb3N0cmFnZW0gLSBleC4gcmVnacOjbywgZXN0YWRvLCBiaW9tYSkKCi0gICBgQXJlYWA6IHZldG9yIG51bcOpcmljbyBjb250ZW5kbyBhIMOhcmVhIGRvIGVzdHJhdG87CgotICAgYFNhbXBsZS5MYWJlbGA6IHZldG9yIG7Dum1lcmljbyBjb250ZW5kbyBhIGlkZW50aWRhZGUgKElEKSBkbyB0cmFuc2VjdG8KCi0gICBgb2JqZWN0YDogbm9tZSBhZGljaW9uYWwsIHZlciBzZcOnw6NvIDY7CgotICAgYGRldGVjdGVkYDogbm9tZSBhZGljaW9uYWwsIHZlciBzZcOnw6NvIDY7CgotICAgYEVmZm9ydGA6IHZldG9yIG7Dum1lcmljbyBjb250ZW5kbyBvIGVzZm9yw6dvIGRvIHRyYW5zZWN0byAocGFyYSBsaW5oYXMgc2V1IGNvbXByaW1lbnRvLCBwYXJhIHBvbnRvcyBvIG7Dum1lcm8gZGUgdmV6ZXMgcXVlIG8gcG9udG8gZm9pIHZpc2l0YWRvKQoKLSAgIGBzaXplYDogdmV0b3IgbnVtw6lyaWNvIGNvcG50ZW5kbyBvIHRhbWFuaG8gZG8gZ3J1cG8gb2JzZXJ2YWRvOwoKLSAgIGBkaXN0YW5jZWA6IHZldG9yIG51bcOpcmljbyBkZSBkaXN0w6JuY2lhcyBvYnNlcnZhZGFzOwoKLSAgIGBNb250aGA6CgotICAgYE9Cc2A6CgotICAgYFNwYDoKCi0gICBgbWFzYDoKCi0gICBgSEFTYDoKCi0gICBgU3R1ZHkuQXJlYWA6CgpUcmFuc2VjdG9zIHF1ZSBmb3JhbSBhbW9zdHJhZG9zLCBtYXMgcXVlIG7Do28gdGl2ZXJhbSBvYnNlcnZhw6fDtWVzIChuID0gMCkgZGV2ZW0gc2VyIGluY2x1w61kb3Mgbm8gY29uanVudG8gZGUgZGFkb3MgY29tIGBOQWAgbmFzIG9ic2VydmHDp8O1ZXMgZGUgZGlzdMOibmNpYSBlIHF1YWxxdWVyIG91dHJhIGNvdmFyaWFlbCBwYXJhIGEgcXVhbCBuw6NvIHNlIHRlbmhhIG9ic2VydmHDp8Ojby4KCmBgYHtyfQojIGN1dGlhX3RhcF9hcmFwIHw+IAojICAgY29tcGxldGUoUmVnaW9uLkxhYmVsLCBTYW1wbGUuTGFiZWwsIHNwX25hbWUpIHw+IAojICAgZGF0YXRhYmxlKGZpbHRlciA9IGxpc3QocG9zaXRpb24gPSAidG9wIikpCmBgYAoKSm9nYXIgYSBpbXB1dGFjYW8gZGUgYE5BYHMgcHJhIGRlbnRybyBkYSBmdW5jYW8gY2FycmVnYXIgZGFkb3MgY29tcGxldG9zLgoKIyMgRGV0ZXJtaW5hbmRvIGEgZGlzdMOibmNpYSBwYXJhIHRydW5jYXIgb3MgZGFkb3MKCmBgYHtyLCBmaWcuaGVpZ2h0PTE1LCBmaWcud2lkdGg9MTAsIHdhcm5pbmc9RkFMU0V9CiMgZGVzZW5oYSBvIGdyYWZpY28gY29tIGEgZGlzdHJpYnVpY2FvIGRlIGRpc3RhbmNpYXMgcGVycGVuZGljdWxhcmVzCmN1dGlhX3RhcF9hcmFwIHw+IAogIGZpbHRlcihkaXN0YW5jZSA+PSAxLAogICAgICAgICBkaXN0YW5jZSA8PSAxNCkgfD4gCiAgcGxvdGFyX2Rpc3RyaWJ1aWNhb19kaXN0YW5jaWFfaW50ZXJhdGl2bygpCmBgYAoKYGBge3J9CnN1bW1hcnkoY3V0aWFfdGFwX2FyYXAkZGlzdGFuY2UpCmBgYAoKIyMgQWp1c3RhbmRvIGZ1bsOnw7VlcyBkZSBkZXRlY8Onw6NvIG5vIFIKCiMjIyBDdXRpYXMgZGEgUmVzZXggVGFwYWrDs3MtQXJhcGl1bnMgcGFyYSBkaWZlcmVudGVzIGRpc3TDom5jaWFzIGRlIHRydW5jYW1lbnRvCgojIyMjICpIYWxmLU5vcm1hbCogc2VtIHRlcm1vcyBkZSBhanVzdGUgZSBjb20gdGVybW9zIGRlIGFqdXN0ZSBDb3NzZW5vIGUgUG9saW5vbWlhbCBkZSBIZXJtaXRlCgpBanVzdGFuZG8gdW0gbW9kZWxvIGFvIGRhZG9zIGRhcyBjdXRpYXMgKkRhc3lwcm9jdGEgY3JvY29ub3RhKiwgY29uZmlndXJhbmRvIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0gZSB1c2FuZG8gKkhhbGYtbm9ybWFsKiBjb21vICprZXkgZnVuY3Rpb24qIHVzYW5kbyBvIGFyZ3VtZW50byBga2V5YCwgc2VtIHRlcm1vIGRlIGFqdXN0ZS4KCmBgYHtyfQoKY3V0aWFfdGFwX2FyYXBfZmlsdHJhZG8gPC0gY3V0aWFfdGFwX2FyYXAgfD4gCiAgZmlsdGVyKGRpc3RhbmNlID49IDEsCiAgICAgICAgIGRpc3RhbmNlIDw9IDE0KQoKIyBhanVzdGFuZG8gYSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIHBhcmEgdW1hIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byBkZSAyMCwgMTUsIDEwIGUgNSBtZXRyb3MKIyBkc2l0YW5jaWFzIGRlIHRydW5jYW1lbnRvCmRpc3RfdHJ1bmNhbWVudG8gPC0gbGlzdCgKICBgMTQgbWV0cm9zYCA9IDE0LCAKICBgMTIgbWV0cm9zYCA9IDEyLCAKICBgMTAgbWV0cm9zYCA9IDEwLAogIGA3IG1ldHJvc2AgPSA3CikKCiMgS2V5IGZ1bmN0aW9uIC0gSGFsZi1ub3JtYWwgCmN1dGlhX3RhcF9hcmFwX2huIDwtIHB1cnJyOjptYXAoCiAgZGlzdF90cnVuY2FtZW50bywKICBcKC54KSBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9obigKICAgIGN1dGlhX3RhcF9hcmFwX2ZpbHRyYWRvLCAKICAgIHRydW5jYW1lbnRvID0gLngKICApCiAgKQpgYGAKCmBgYHtyfQpjdXRpYV90YXBfYXJhcF9obgpgYGAKCiMjIyMgKkhhemFyZC1SYXRlKiBzZW0gdGVybW9zIGRlIGFqdXN0ZSBlIGNvbSB0ZXJtb3MgZGUgYWp1c3RlIENvc3Nlbm8gZSBQb2xpbm9taWFsIGRlIEhlcm1pdGUKCkFqdXN0YW5kbyB1bSBtb2RlbG8gYW8gZGFkb3MgZGEgY3V0aWEgKkRhc3lwcm9jdGEgY3JvY29ub3RhKiwgY29uZmlndXJhbmRvIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0gZSB1c2FuZG8gKkhhemFyZCByYXRlKiBjb21vICprZXkgZnVuY3Rpb24qIHVzYW5kbyBvIGFyZ3VtZW50byBga2V5YC4KCmBgYHtyfQojIGFqdXN0YW5kbyBhIGZ1bsOnw6NvIGRlIGRldGVjw6fDo28gcGFyYSB1bWEgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIGRlIDIwLCAxNSwgMTAgZSA1IG1ldHJvcwojIEtleSBmdW5jdGlvbiAtIEhhemFyZC1yYXRlCmN1dGlhX3RhcF9hcmFwX2hyIDwtIHB1cnJyOjptYXAoCiAgZGlzdF90cnVuY2FtZW50bywKICBcKC54KSBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9ocigKICAgIGN1dGlhX3RhcF9hcmFwX2ZpbHRyYWRvLCAKICAgIHRydW5jYW1lbnRvID0gLngKICApCiAgKQpgYGAKCiMjIyMgKlVuaWZvcm0qIHNlbSB0ZXJtb3MgZGUgYWp1c3RlIGUgY29tIHRlcm1vcyBkZSBhanVzdGUgQ29zc2VubyBlIFBvbGlub21pYWwgZGUgSGVybWl0ZQoKQWp1c3RhbmRvIHVtIG1vZGVsbyBhbyBkYWRvcyBkYXMgY3V0aWFzICpEYXN5cHJvY3RhIGNyb2Nvbm90YSosIGNvbmZpZ3VyYW5kbyB1bWEgZGlzdMOibmNpYSBsaW1pdGUgZGUgMjBtIGUgdXNhbmRvICpVbmlmb3JtKiBjb21vICprZXkgZnVuY3Rpb24qIHVzYW5kbyBvIGFyZ3VtZW50byBga2V5YCwgc2VtIHRlcm1vIGRlIGFqdXN0ZS4KCmBgYHtyfQojIGFqdXN0YW5kbyBhIGZ1bsOnw6NvIGRlIGRldGVjw6fDo28gcGFyYSB1bWEgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIGRlIDIwLCAxNSwgMTAgZSA1IG1ldHJvcwojIEtleSBmdW5jdGlvbiAtIFVuaWZvcm0KY3V0aWFfdGFwX2FyYXBfdW5pZiA8LSBwdXJycjo6bWFwKAogIGRpc3RfdHJ1bmNhbWVudG8sCiAgXCgueCkgYWp1c3RlX21vZGVsb3NfZGlzdGFuY2VfdW5pZigKICAgIGN1dGlhX3RhcF9hcmFwLCAKICAgIHRydW5jYW1lbnRvID0gLngKICApCikKYGBgCgojIyMjIyMgU2VsZcOnw6NvIGRlIG1vZGVsb3MKCmBgYHtyfQpzdW1tYXJpemVfZHNfbW9kZWxzKAogIGN1dGlhX3RhcF9hcmFwX2huJGAxNCBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV90YXBfYXJhcF9obiRgMTQgbWV0cm9zYCRDb3NzZW5vLAogIGN1dGlhX3RhcF9hcmFwX2huJGAxNCBtZXRyb3NgJGBIZXJtaXRlIHBvbGlub21pYWxgLApjdXRpYV90YXBfYXJhcF9ociRgMTQgbWV0cm9zYCRgU2VtIHRlcm1vYCwKY3V0aWFfdGFwX2FyYXBfaHIkYDE0IG1ldHJvc2AkQ29zc2VubywKY3V0aWFfdGFwX2FyYXBfaHIkYDE0IG1ldHJvc2AkYFBvbGlub21pYWwgc2ltcGxlc2AsCmN1dGlhX3RhcF9hcmFwX3VuaWYkYDE0IG1ldHJvc2AkQ29zc2VubywKY3V0aWFfdGFwX2FyYXBfdW5pZiRgMTQgbWV0cm9zYCRgUG9saW5vbWlhbCBzaW1wbGVzYAopCmBgYAoKYGBge3J9CnN1bW1hcml6ZV9kc19tb2RlbHMoCiAgY3V0aWFfdGFwX2FyYXBfaG4kYDEyIG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX3RhcF9hcmFwX2huJGAxMiBtZXRyb3NgJENvc3Nlbm8sCiAgY3V0aWFfdGFwX2FyYXBfaG4kYDEyIG1ldHJvc2AkYEhlcm1pdGUgcG9saW5vbWlhbGAsCmN1dGlhX3RhcF9hcmFwX2hyJGAxMiBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV90YXBfYXJhcF9ociRgMTIgbWV0cm9zYCRDb3NzZW5vLApjdXRpYV90YXBfYXJhcF9ociRgMTIgbWV0cm9zYCRgUG9saW5vbWlhbCBzaW1wbGVzYCwKY3V0aWFfdGFwX2FyYXBfdW5pZiRgMTIgbWV0cm9zYCRDb3NzZW5vLApjdXRpYV90YXBfYXJhcF91bmlmJGAxMiBtZXRyb3NgJGBQb2xpbm9taWFsIHNpbXBsZXNgCikKYGBgCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBjdXRpYV90YXBfYXJhcF9obiRgMTAgbWV0cm9zYCRgU2VtIHRlcm1vYCwKY3V0aWFfdGFwX2FyYXBfaG4kYDEwIG1ldHJvc2AkQ29zc2VubywKICBjdXRpYV90YXBfYXJhcF9obiRgMTAgbWV0cm9zYCRgSGVybWl0ZSBwb2xpbm9taWFsYCwKY3V0aWFfdGFwX2FyYXBfaHIkYDEwIG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX3RhcF9hcmFwX2hyJGAxMCBtZXRyb3NgJENvc3Nlbm8sCmN1dGlhX3RhcF9hcmFwX2hyJGAxMCBtZXRyb3NgJGBQb2xpbm9taWFsIHNpbXBsZXNgLApjdXRpYV90YXBfYXJhcF91bmlmJGAxMCBtZXRyb3NgJENvc3Nlbm8sCmN1dGlhX3RhcF9hcmFwX3VuaWYkYDEwIG1ldHJvc2AkYFBvbGlub21pYWwgc2ltcGxlc2AKKQpgYGAKCmBgYHtyfQpzdW1tYXJpemVfZHNfbW9kZWxzKAogIGN1dGlhX3RhcF9hcmFwX2huJGA3IG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX3RhcF9hcmFwX2huJGA3IG1ldHJvc2AkQ29zc2VubywKICBjdXRpYV90YXBfYXJhcF9obiRgNyBtZXRyb3NgJGBIZXJtaXRlIHBvbGlub21pYWxgLApjdXRpYV90YXBfYXJhcF9ociRgNyBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV90YXBfYXJhcF9ociRgNyBtZXRyb3NgJENvc3Nlbm8sCmN1dGlhX3RhcF9hcmFwX2hyJGA3IG1ldHJvc2AkYFBvbGlub21pYWwgc2ltcGxlc2AsCmN1dGlhX3RhcF9hcmFwX3VuaWYkYDcgbWV0cm9zYCRDb3NzZW5vLApjdXRpYV90YXBfYXJhcF91bmlmJGA3IG1ldHJvc2AkYFBvbGlub21pYWwgc2ltcGxlc2AKKQpgYGAKCiMjIyMgUmVzdW1pciBvIHJlc3VsdGFkbyBkb3MgbW9kZWxvcwoKTyBxdWUgdGVtIHF1ZSB0ZXI/CgpPcyBncsOhZmljb3MgKHByb2JhYmlsaWRhZGUgZGUgZGV0ZWPDp8OjbyBwZWxhIGRpc3TDom5jaWEsIGNvbSBhIGN1cnZhIGFqdXN0YWRhLCBleGVtcGxvIGFiYWl4bywgZmF6ZXIgbm8gZ2dwbG90KSwgcmVzdWx0YWRvIGRvIGdvb2RuZXNzIG9mIGZpdCAoZ29mX2RzKCkpLCBjYWRhIG1vZGVsbyB2YWkgdGVyIHF1ZSB0ZXIgdW0gbm9tZSBkaWZlcmVudGUgbnVtYSB0YWJlbGEoPykKCmBgYHtyfQpwbG90KGN1dGlhX3RhcF9hcmFwX2huLCBicmVha3MgPSBzZXEoMCwgMjAsIDIuNSkpCnBsb3QoY3V0aWFfdGFwX2FyYXBfaG5faGVybSwgYnJlYWtzID0gc2VxKDAsIDIwLCAyLjUpKQpwbG90KGN1dGlhX3RhcF9hcmFwX2huX2NvcywgYnJlYWtzID0gc2VxKDAsIDIwLCAyLjUpKQpwbG90KGN1dGlhX3RhcF9hcmFwX2hyLCBicmVha3MgPSBzZXEoMCwgMjAsIDIuNSkpCnBsb3QoY3V0aWFfdGFwX2FyYXBfaHJfcG9seSwgYnJlYWtzID0gc2VxKDAsIDIwLCAyLjUpKQpwbG90KGN1dGlhX3RhcF9hcmFwX2hyX2NvcywgYnJlYWtzID0gc2VxKDAsIDIwLCAyLjUpKQpgYGAKCiMjIENoZWNhZ2VtIGUgc2VsZcOnw6NvIGRlIG1vZGVsb3MKClBvZGVtb3MgdXNhciBhIGZ1bsOnw6NvIGBzdW1tYXJ5YCBwYXJhIG9idGVyIGluZm9ybWHDp8O1ZXMgaW1wb3J0YW50ZXMgc29icmUgbyBtb2RlbG8uCgpgYGB7cn0KCmxpc3RhX21vZGVsb3MgPC0gbGlzdCgKICBjdXRpYV90YXBfYXJhcF9obiwKICBjdXRpYV90YXBfYXJhcF9obl9oZXJtLAogIGN1dGlhX3RhcF9hcmFwX2huX2NvcywKICBjdXRpYV90YXBfYXJhcF9ociwKICBjdXRpYV90YXBfYXJhcF9ocl9wb2x5LAogIGN1dGlhX3RhcF9hcmFwX2hyX2NvcwopCgpwdXJycjo6bWFwKGxpc3RhX21vZGVsb3MsIFwoeCkgc3VtbWFyeSh4KSkKYGBgCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBjdXRpYV90YXBfYXJhcF9obiwKICBjdXRpYV90YXBfYXJhcF9obl9oZXJtLAogIGN1dGlhX3RhcF9hcmFwX2huX2NvcywKICBjdXRpYV90YXBfYXJhcF9ociwKICBjdXRpYV90YXBfYXJhcF9ocl9wb2x5LAogIGN1dGlhX3RhcF9hcmFwX2hyX2NvcwopCgoKYGBgCgpPIHJlc3VsdGFkbyBpbmNsdWkgZGV0YWxoZXMgc29icmUgbyBkYWRvIGUgYSBlc3BlY2lmaWNhw6fDo28gZG8gbW9kZWxvLCBhc3NpbSBjb21vIGRvcyBjb2VmaWNpZW50ZXMgKCRcYmV0YV97an0kKSBlIHN1YSBpbmNldGV6YSwgYSBtw6lkaWEgZG8gdmFsb3IgZGUgZGV0ZWN0YWJpbGlkYWRlIGUgc3VhIGluY2VydGV6YSBlIHVtYSBlc3RpbWF0aXZhIGRhIGFidW5kw6JuY2lhIG5hIMOhcmVhIGNvYmVydGEgcGVsYSBhbW9zdHJhZ2VtIChzZW0gbGV2YXIgZW0gY29uc2lkZXJhw6fDo28gbyB0YW1hbmhvIGRvcyBhZ3J1cGFtZW50b3MsIG91IGJhbmRvcykuCgojIyMgQm9uZGFkZSBkZSBhanVzdGUKClBhcmEgdmlzdWFsaXphciBxdcOjbyBiZW0gYSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIHNlIGFqdXN0YSBhb3MgZGFkb3MgcXVhbnRvIHRlbW9zIGFzIGRpc3TDom5jaWFzIGV4YXRhcyBwb2RlbW9zIHVzYXIgdW0gcGxvdCBkZSBxdWFudGlzIGVtcMOtcmljb3MgeCB0ZcOzcmljb3MgKFEtUSBwbG90KS4gRWxlIGNvbXBhcmEgYSBmdW7Dp8OjbyBkZSBkaXN0cmlidWnDp8OjbyBjdW11bGF0aXZhIChDREYpIGRvcyB2YWxvcmVzIGFqdXN0YWRvcyBkYSBmdW7Dp8OjbyBkZXRlY8Onw6NvIGEgZGlzdHJpYnVpw6fDo28gZW1ww61yaWNhIGRvcyBkYWRvcyAoRURGKS4KClRhbWLDqW0gcG9kZW1vcyB1c2FyIG8gdGVzdGUgZGUgQ3JhbcOpci12b24gTWlzZXMgcGFyYSB0ZXN0YXIgc2Ugb3MgcG9udG9zIGRhIEVERiBlIGRhIENERiB0ZW0gb3JpZ2VtIG5hIG1lc21hIGRpc3RyaWJ1acOnw6NvLiBPIHRlc3RlIHVzYSBhIHNvbWEgZGUgdG9kYXMgYXMgZGlzdMOibmNpYXMgZW50cmUgdW0gcG9udG8gZSBhIGxpbmhhIHkgPSB4IHBhcmEgZm9ybWFyIGEgZXN0YXTDrXN0aWNhIGEgc2VyIHRlc3RhZGEuIFVtIHJlc3VsdGFkbyBzaWduaWZpY2F0aXZvIGZvcm5lY2UgZXZpZMOqbmNpYSBjb250cmEgYSBoaWlww7N0ZXNlIG51bGEsIHN1Z2VyaW5kbyBxdWUgbyBtb2RlbG8gbsOjbyBzZSBhanVzdGEgYmVtIGFvcyBkYWRvcy4KCmBgYHtyfQojIGFqdXN0YW5kbyB1bSBtb2RlbG8gSGFsZi1ub3JtYWwKY3V0aWFfaG4gPC0gZHMoZGF0YSA9IGN1dGlhX3RhcF9hcmFwXzE1LAogICAgICAgICAgICAgICAgIHRydW5jYXRpb24gPSAyMCwKICAgICAgICAgICAgICAgICB0cmFuc2VjdCA9ICJsaW5lIiwKICAgICAgICAgICAgICAgICBrZXkgPSAiaG4iLCAKICAgICAgICAgICAgICAgICBhZGp1c3RtZW50ID0gTlVMTCkKCiMgY29uZHV6aW5kbyBvIHRlc3RlIGRmZSBib25kYWRlZGUgYWp1c3RlIGRlIENyYW1lci12b24gTWlzZXMKZ29mX2RzKGN1dGlhX2huKQoKZ29mX2RzKGN1dGlhX2hyX3RpbWUpCmBgYAoKTyByZXN1dGxhZG8gZG8gdGVzdGUgYXBvbnRhIHF1ZSBvIG1vZGVsbyAqSGFsZi1ub3JtYWwqIGRldmUgc2VyIGRlc2NhcnRhZG8uCgpUZXN0ZXMgZGUgYm9uZGFkZSBkZSBhanVzdGUgZGUgY2hpLXF1YWRyYWRvIHPDo28gZ2VyYWRvcyB1c2FuZG8gYSBmdW7Dp8OjbyBgZ29mX2RzYCBxdWFuZG8gYXMgZGlzdMOibmNpYXMgZm9ybmVjZWlkYXMgZXN0w6NvIGNhdGVnb3JpemFkYXMuCgojIyMgU2VsZcOnw6NvIGRlIE1vZGVsb3MKClVtYSB2ZXogcXVlIHRlbW9zIHVtIGNvbmp1bnRvIGRlIG1vZGVsb3MgcGxhdXPDrXZlaXMsIHBvZGVtb3MgdXRpbGl6YXIgbyBjaXJ0w6lyaW9kZSBpbmZvcm1hw6fDo29kZSBBa2Fpa2UgKEFJQykgcGFyYSBzZWxlY2lvbmFyIGVudHJlIG9zIG1vZGVsb3MgbyBxdWUgbWVsaG9yIHNlIGFqdXN0YSBhb3MgZGFkb3MgdXRpbGl6YW5kbyBhIGZ1bsOnw6NvIGBzdW1tYXJpemVfZHNfbW9kZWxzYC4KCmBgYHtyfQojIGdlcmFuZG8gdW1hIHRhYmVsYSBkZSBzZWxlw6fDo28gZGUgbW9kZWxvcyB1c2FuZG8gQUlDCnN1bW1hcml6ZV9kc19tb2RlbHMoY3V0aWFfaG4sIGN1dGlhX2hyX3RpbWUsIGN1dGlhX2hyX3RpbWVfc2l6ZSkKYGBgCgpPIG1lbGhvciBtb2RlbG8gw6kgbyBIYXphcmQtcmF0ZSBjb20gdGVtcG8gZGUgc2Vuc28gZSB0YW1hbmhvIGRvIGdydXBvIGNvbW8gY292YXJpw6F2ZWlzLgoKIyMgRXN0aW1hbmRvIGEgYWJ1bmTDom5jaWEgZSBhIHZhcmnDom5jaWEKCiMjIyBFc3RpbWFuZG8gYWJ1bmTDom5jaWEgZSB2YXJpw6JuY2lhIG5vIFIKClBhcmEgb2J0ZXIgYSBhYnVuZMOibmNpYSBuYSByZWdpw6NvIGRlIGVzdHVkbywgcHJpbWVpcm8gY2FsY3VsYW1vcyBhIGFidW5kw6JuY2lhIG5hIMOhcmVhIGFtb3N0cmFkYSBwYXJhIG9idGVyICROX2MkIGUgZW0gc2VndWlkYSBlc2NhbG9uYW1vcyBlc3NlIHZhbG9yIHBhcmEgdG9kYSBhIMOhcmVhIGRlIGVzdHVkbyBtdWx0aXBsaWNhbmRvICROX2MkIHBlbGEgcmF6w6NvIGVudHJlIGEgw6FyZWEgYW1vc3RyYWRhIGUgYSDDoXJlYSBkYSByZWdpw6NvLiBQYXJhIGVzdGltYXIgYSBhYnVuZMOibmNpYSBuYSDDoXJlYSBhbW9zdHJhZGEsIHV0aWxpemFtb3MgYXMgZXN0aW1hdGl2YXMgZGUgcHJvYmFiaWxpZGFkZSBkZSBkZXRlY8Onw6NvIG5vIGVzdGltYWRvciBkZSBIb3J2aXR6LVRob21wc29uLgoKUXVhbmRvIGZvcm5lY2Vtb3Mgb3MgZGFkb3Mgbm8gZm9ybWF0byBjb3JyZXRvICgiZmxhdGZpbGUiKSBgZHNgIGlyw6EgYXV0b21hdGljYW1lbnRlIGNhbGN1bGFyIGFzIGVzdGltYXRpdmFzIGRlIGFidW5kw6JuY2lhIGJhc2VhZG8gbmFzIGluZm9ybWHDp8O1ZXMgZGUgYW1vc3RyYWdlbSBwcmVzZW50YSBub3MgZGFkb3MuCgpgYGB7cn0Kc3VtbWFyeShjdXRpYV9obikKYGBgCgoxLiAgU3VtbWFyeSBzdGF0aXN0aWNzOiBmb3JuZWNlIGFzIMOhcmVhcywgYcWVZWEgZGUgYW1vc3RyYWdlbSwgZXNmb3LDp28sIG7Dum1lcm8gZGUgb2JzZXJ2YcOnw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zLCB0YXhhIGRlIGVuY29udHJvLCBzZXVzIGVycm9zIHBhZHLDtWVzIGUgY29lZmljaWVudGVzIGRlIHZhcmlhw6fDo28gcGFyYSBjYWRhIGVzdHJhdG87CgoyLiAgQWJ1bmRhbmNlOiBmb3JuZWNlIGVzdGltYXRpdmFzLCBlcnJvcyBwYWRyw7VlcywgY29lZmljaWVudGVzZGUgdmFyaWHDp8OjbywgaW50ZXJ2YWxvcyBkZSBjb25maWFuw6dhIGluZmVyaW9yIGUgc3VwZXJpb3IsIGdyYXVzIGRlIGxpYmVyZGFkZSBwYXJhIGEgZXN0aW1hdGl2YSBkZSBhYnVuZMOibmNpYSBkZSBjYWRhIGVzdHJhdG87CgozLiAgRGVuc2lkYWRlOiBsaXN0YSBhcyBtZXNtYXMgZXN0YXTDrXN0aWNhcyBkZSBBYnVuZGFuY2UsIHPDsyBxdWUgcGFyYSBkZW5zaWRhZGUuCgojIyAqKkZ1bsOnw7VlcyBFeHBsb3JhdMOzcmlhcyBBZGljaW9uYWlzKioKCmBjb250YXJfbl9yZXBldGljb2VzX3RyaWxoYSgpYCAtIGNvbnRhIG8gbsO6bWVybyBkZSB2ZXplcyBxdWUgY2FkYSB0cmlsaGEgZm9pIHZpc2l0YWRhCgojIyBBZGljaW9uYW5kbyBjb3ZhcmlhdmVsCgpBanVzdGUgKkhlcm1pdGUgcG9sbHlub21pYWwqIHVzYSBvZCBjw7NkaWdvIGAiaGVybSJgIGUgcG9saW5vbWlhbCBzaW1wbGVzIGAicG9seSJgLgoKUG9kZW1vcyBpbmNsdWlyIGNvdmFyacOhdmVpcyB1dGlsaXphbmRvIG8gYXJndW1lbnRvIGBmb3JtdWxhID0gfiAuLi5gLiBBYmFpeG8sIGVzdMOhIGVzcGVjaWZpY2FkbyB1bSBtb2RlbG8gIkhhemFyZC1yYXRlIiBwYXJhIG9zIGRhZG9zIGRlIGN1dGlhIHEgdWUgaW5jbHVpIG8gdGVtcG8gZGUgc2Vuc28gY29tbyBjb3ZhcmnDoXZlbCBlIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0uCgpgYGB7cn0KY3V0aWFfaHJfdGltZSA8LSBjdXRpYV90YXBfYXJhcF8xNSB8PiAKICBkcyh0cnVuY2F0aW9uID0gMjAsCiAgICAga2V5ID0gImhyIiwKICAgICBmb3JtdWxhID0gfiBjZW5zZV90aW1lKQpgYGAKCkFkaWNpb25hbmRvIHVtYSBzZWd1bmRhIGNvdmFyacOhdmVsOiB0YW1hbmhvIGRvIGdydXBvLgoKYGBge3J9CmN1dGlhX2hyX3RpbWVfc2l6ZSA8LSBkcyhkYXRhID0gY3V0aWFfdGFwX2FyYXBfMTUsCiAgICAgICAgICAgICAgICAgICAgIHRydW5jYXRpb24gPSAyMCwKICAgICAgICAgICAgICAgICAgICAgdHJhbnNlY3QgPSAibGluZSIsCiAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJociIsCiAgICAgICAgICAgICAgICAgICAgIGZvcm11bGEgPSB+IGNlbnNlX3RpbWUgKyBzaXplKQpgYGAKCmBgYHtyfQpwbG90KGN1dGlhX2hyX3RpbWUpCnBsb3QoY3V0aWFfaHJfdGltZV9zaXplKQpgYGAKCiMjIyBDdXRpYXMgZGEgRVNFQyBUZXJyYSBkbyBNZWlvIHBhcmEgZGlmZXJlbnRlcyBkaXN0w6JuY2lhcyBkZSB0cnVuY2FtZW50bwoKYGBge3J9CmN1dGlhX2VzZWNfdGVycmFfbWVpbyA8LSB0cmFuc2Zvcm1hcl9wYXJhX2Rpc3RhbmNlUl9jb3ZhcmlhdmVpcygpIHw+IAogIGZpbHRlcigKICAgIFJlZ2lvbi5MYWJlbCA9PSAiRXNlYyBkYSBUZXJyYSBkbyBNZWlvIiwKICAgIHNwX25hbWUgPT0gIkRhc3lwcm9jdGEgY3JvY29ub3RhIgogICkgfD4gCiAgZHJvcF9uYShkaXN0YW5jZSkKICAKYGBgCgpgYGB7cn0KIyBkZXNlbmhhIG8gZ3JhZmljbyBjb20gYSBkaXN0cmlidWljYW8gZGUgZGlzdGFuY2lhcyBwZXJwZW5kaWN1bGFyZXMKY3V0aWFfZXNlY190ZXJyYV9tZWlvIHw+IAogIGZpbHRlcihkaXN0YW5jZSA+PSAxLAogICAgICAgICBkaXN0YW5jZSA8IDE1KSB8PiAKICBwbG90YXJfZGlzdHJpYnVpY2FvX2Rpc3RhbmNpYV9pbnRlcmF0aXZvKGxhcmd1cmFfY2FpeGEgPSAxKQpgYGAKCiMjIyMgKkhhbGYtTm9ybWFsKiBzZW0gdGVybW9zIGRlIGFqdXN0ZSBlIGNvbSB0ZXJtb3MgZGUgYWp1c3RlIENvc3Nlbm8gZSBQb2xpbm9taWFsIGRlIEhlcm1pdGUKCkFqdXN0YW5kbyB1bSBtb2RlbG8gYW8gZGFkb3MgZGFzIGN1dGlhcyAqRGFzeXByb2N0YSBjcm9jb25vdGEqLCBjb25maWd1cmFuZG8gdW1hIGRpc3TDom5jaWEgbGltaXRlIGRlIDIwbSBlIHVzYW5kbyAqSGFsZi1ub3JtYWwqIGNvbW8gKmtleSBmdW5jdGlvbiogdXNhbmRvIG8gYXJndW1lbnRvIGBrZXlgLCBzZW0gdGVybW8gZGUgYWp1c3RlLgoKYGBge3J9CmN1dGlhX2VzZWNfdGVycmFfbWVpb19maWx0cmFkbwpgYGAKCmBgYHtyfQpjdXRpYV9lc2VjX3RlcnJhX21laW9fZmlsdHJhZG8gPC0gY3V0aWFfZXNlY190ZXJyYV9tZWlvIHw+IAogIGZpbHRlcihkaXN0YW5jZSA+PSAxLAogICAgICAgICBkaXN0YW5jZSA8IDE1KQojIGFqdXN0YW5kbyBhIGZ1bsOnw6NvIGRlIGRldGVjw6fDo28gcGFyYSB1bWEgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIGRlIDIwLCAxNSwgMTAgZSA1IG1ldHJvcwojIGRzaXRhbmNpYXMgZGUgdHJ1bmNhbWVudG8KZGlzdF90cnVuY2FtZW50byA8LSBsaXN0KAogICNgMjAgbWV0cm9zYCA9IDIwLCAKICBgMTUgbWV0cm9zYCA9IDE1LCAKICBgMTIgbWV0cm9zYCA9IDEyLAogIGAxMCBtZXRyb3NgID0gMTAKKQoKIyBLZXkgZnVuY3Rpb24gLSBIYWxmLW5vcm1hbCAKY3V0aWFfZXNlY190ZXJyYV9tZWlvX2huIDwtIHB1cnJyOjptYXAoCiAgZGlzdF90cnVuY2FtZW50bywKICBcKC54KSBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9obigKICAgIGN1dGlhX2VzZWNfdGVycmFfbWVpb19maWx0cmFkbywgCiAgICB0cnVuY2FtZW50byA9IC54CiAgKQogICkKYGBgCgpgYGB7cn0KY3V0aWFfZXNlY190ZXJyYV9tZWlvX2huCmBgYAoKIyMjIyAqSGF6YXJkLVJhdGUqIHNlbSB0ZXJtb3MgZGUgYWp1c3RlIGUgY29tIHRlcm1vcyBkZSBhanVzdGUgQ29zc2VubyBlIFBvbGlub21pYWwgZGUgSGVybWl0ZQoKQWp1c3RhbmRvIHVtIG1vZGVsbyBhbyBkYWRvcyBkYSBjdXRpYSAqRGFzeXByb2N0YSBjcm9jb25vdGEqLCBjb25maWd1cmFuZG8gdW1hIGRpc3TDom5jaWEgbGltaXRlIGRlIDIwbSBlIHVzYW5kbyAqSGF6YXJkIHJhdGUqIGNvbW8gKmtleSBmdW5jdGlvbiogdXNhbmRvIG8gYXJndW1lbnRvIGBrZXlgLgoKYGBge3J9CiMgYWp1c3RhbmRvIGEgZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBwYXJhIHVtYSBkaXN0YW5jaWEgZGUgdHJ1bmNhbWVudG8gZGUgMjAsIDE1LCAxMCBlIDUgbWV0cm9zCiMgS2V5IGZ1bmN0aW9uIC0gSGF6YXJkLXJhdGUKY3V0aWFfZXNlY190ZXJyYV9tZWlvX2hyIDwtIHB1cnJyOjptYXAoCiAgZGlzdF90cnVuY2FtZW50bywKICBcKC54KSBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9ocigKICAgIGN1dGlhX2VzZWNfdGVycmFfbWVpb19maWx0cmFkbywgCiAgICB0cnVuY2FtZW50byA9IC54CiAgKQogICkKYGBgCgojIyMjICpVbmlmb3JtKiBzZW0gdGVybW9zIGRlIGFqdXN0ZSBlIGNvbSB0ZXJtb3MgZGUgYWp1c3RlIENvc3Nlbm8gZSBQb2xpbm9taWFsIGRlIEhlcm1pdGUKCkFqdXN0YW5kbyB1bSBtb2RlbG8gYW8gZGFkb3MgZGFzIGN1dGlhcyAqRGFzeXByb2N0YSBjcm9jb25vdGEqLCBjb25maWd1cmFuZG8gdW1hIGRpc3TDom5jaWEgbGltaXRlIGRlIDIwbSBlIHVzYW5kbyAqVW5pZm9ybSogY29tbyAqa2V5IGZ1bmN0aW9uKiB1c2FuZG8gbyBhcmd1bWVudG8gYGtleWAsIHNlbSB0ZXJtbyBkZSBhanVzdGUuCgpgYGB7cn0KIyBhanVzdGFuZG8gYSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIHBhcmEgdW1hIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byBkZSAyMCwgMTUsIDEwIGUgNSBtZXRyb3MKIyBLZXkgZnVuY3Rpb24gLSBVbmlmb3JtCmN1dGlhX2VzZWNfdGVycmFfbWVpb191bmlmIDwtIHB1cnJyOjptYXAoCiAgZGlzdF90cnVuY2FtZW50bywKICBcKC54KSBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV91bmlmKAogICAgY3V0aWFfdGFwX2FyYXAsIAogICAgdHJ1bmNhbWVudG8gPSAueAogICkKICApCmBgYAoKIyMjIyMjIFNlbGXDp8OjbyBkZSBtb2RlbG9zCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBjdXRpYV9lc2VjX3RlcnJhX21laW9faG4kYDIwIG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX2VzZWNfdGVycmFfbWVpb19obiRgMjAgbWV0cm9zYCRDb3NzZW5vLAogIGN1dGlhX2VzZWNfdGVycmFfbWVpb19obiRgMjAgbWV0cm9zYCRgSGVybWl0ZSBwb2xpbm9taWFsYCwKY3V0aWFfZXNlY190ZXJyYV9tZWlvX2hyJGAyMCBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV9lc2VjX3RlcnJhX21laW9faHIkYDIwIG1ldHJvc2AkQ29zc2VubywKY3V0aWFfZXNlY190ZXJyYV9tZWlvX2hyJGAyMCBtZXRyb3NgJGBQb2xpbm9taWFsIHNpbXBsZXNgLApjdXRpYV9lc2VjX3RlcnJhX21laW9fdW5pZiRgMjAgbWV0cm9zYCRDb3NzZW5vLApjdXRpYV9lc2VjX3RlcnJhX21laW9fdW5pZiRgMjAgbWV0cm9zYCRgUG9saW5vbWlhbCBzaW1wbGVzYAopCmBgYAoKYGBge3J9CnN1bW1hcml6ZV9kc19tb2RlbHMoCiAgY3V0aWFfZXNlY190ZXJyYV9tZWlvX2huJGAxNSBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV9lc2VjX3RlcnJhX21laW9faG4kYDE1IG1ldHJvc2AkQ29zc2VubywKICBjdXRpYV9lc2VjX3RlcnJhX21laW9faG4kYDE1IG1ldHJvc2AkYEhlcm1pdGUgcG9saW5vbWlhbGAsCmN1dGlhX2VzZWNfdGVycmFfbWVpb19ociRgMTUgbWV0cm9zYCRgU2VtIHRlcm1vYCwKY3V0aWFfZXNlY190ZXJyYV9tZWlvX2hyJGAxNSBtZXRyb3NgJENvc3Nlbm8sCmN1dGlhX2VzZWNfdGVycmFfbWVpb19ociRgMTUgbWV0cm9zYCRgUG9saW5vbWlhbCBzaW1wbGVzYCwKY3V0aWFfZXNlY190ZXJyYV9tZWlvX3VuaWYkYDE1IG1ldHJvc2AkQ29zc2VubywKY3V0aWFfZXNlY190ZXJyYV9tZWlvX3VuaWYkYDE1IG1ldHJvc2AkYFBvbGlub21pYWwgc2ltcGxlc2AKKQpgYGAKCmBgYHtyfQpzdW1tYXJpemVfZHNfbW9kZWxzKAogIGN1dGlhX2VzZWNfdGVycmFfbWVpb19obiRgMTAgbWV0cm9zYCRgU2VtIHRlcm1vYCwKY3V0aWFfZXNlY190ZXJyYV9tZWlvX2huJGAxMCBtZXRyb3NgJENvc3Nlbm8sCiAgY3V0aWFfZXNlY190ZXJyYV9tZWlvX2huJGAxMCBtZXRyb3NgJGBIZXJtaXRlIHBvbGlub21pYWxgLApjdXRpYV9lc2VjX3RlcnJhX21laW9faHIkYDEwIG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX2VzZWNfdGVycmFfbWVpb19ociRgMTAgbWV0cm9zYCRDb3NzZW5vLApjdXRpYV9lc2VjX3RlcnJhX21laW9faHIkYDEwIG1ldHJvc2AkYFBvbGlub21pYWwgc2ltcGxlc2AsCmN1dGlhX2VzZWNfdGVycmFfbWVpb191bmlmJGAxMCBtZXRyb3NgJENvc3Nlbm8sCmN1dGlhX2VzZWNfdGVycmFfbWVpb191bmlmJGAxMCBtZXRyb3NgJGBQb2xpbm9taWFsIHNpbXBsZXNgCikKYGBgCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBjdXRpYV9lc2VjX3RlcnJhX21laW9faG4kYDEyIG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX2VzZWNfdGVycmFfbWVpb19obiRgMTIgbWV0cm9zYCRDb3NzZW5vLAogIGN1dGlhX2VzZWNfdGVycmFfbWVpb19obiRgMTIgbWV0cm9zYCRgSGVybWl0ZSBwb2xpbm9taWFsYCwKY3V0aWFfZXNlY190ZXJyYV9tZWlvX2hyJGAxMiBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV9lc2VjX3RlcnJhX21laW9faHIkYDEyIG1ldHJvc2AkQ29zc2VubywKY3V0aWFfZXNlY190ZXJyYV9tZWlvX2hyJGAxMiBtZXRyb3NgJGBQb2xpbm9taWFsIHNpbXBsZXNgLApjdXRpYV9lc2VjX3RlcnJhX21laW9fdW5pZiRgMTIgbWV0cm9zYCRDb3NzZW5vLApjdXRpYV9lc2VjX3RlcnJhX21laW9fdW5pZiRgMTIgbWV0cm9zYCRgUG9saW5vbWlhbCBzaW1wbGVzYAopCmBgYAoKIyMjIEN1dGlhcyBkYSBQYXJuYSBkYSBTZXJyYSBkbyBQYXJkbyBwYXJhIGRpZmVyZW50ZXMgZGlzdMOibmNpYXMgZGUgdHJ1bmNhbWVudG8KCmBgYHtyfQpjdXRpYV9wYXJuYV9zZXJyYV9wYXJkbyA8LSB0cmFuc2Zvcm1hcl9wYXJhX2Rpc3RhbmNlUl9jb3ZhcmlhdmVpcygpIHw+IAogIGZpbHRlcigKICAgIFJlZ2lvbi5MYWJlbCA9PSAiUGFybmEgZGEgU2VycmEgZG8gUGFyZG8iLAogICAgc3BfbmFtZSA9PSAiRGFzeXByb2N0YSBjcm9jb25vdGEiCiAgKSB8PiAKICBkcm9wX25hKGRpc3RhbmNlKQogIApgYGAKCmBgYHtyfQojIGRlc2VuaGEgbyBncmFmaWNvIGNvbSBhIGRpc3RyaWJ1aWNhbyBkZSBkaXN0YW5jaWFzIHBlcnBlbmRpY3VsYXJlcwpjdXRpYV9wYXJuYV9zZXJyYV9wYXJkbyB8PiAKICBmaWx0ZXIoZGlzdGFuY2UgPCAxNSwKICAgICAgICAgZGlzdGFuY2UgPiAwKSB8PiAKICBwbG90YXJfZGlzdHJpYnVpY2FvX2Rpc3RhbmNpYV9pbnRlcmF0aXZvKCkKYGBgCgojIyMjICpIYWxmLU5vcm1hbCogc2VtIHRlcm1vcyBkZSBhanVzdGUgZSBjb20gdGVybW9zIGRlIGFqdXN0ZSBDb3NzZW5vIGUgUG9saW5vbWlhbCBkZSBIZXJtaXRlCgpBanVzdGFuZG8gdW0gbW9kZWxvIGFvIGRhZG9zIGRhcyBjdXRpYXMgKkRhc3lwcm9jdGEgY3JvY29ub3RhKiwgY29uZmlndXJhbmRvIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0gZSB1c2FuZG8gKkhhbGYtbm9ybWFsKiBjb21vICprZXkgZnVuY3Rpb24qIHVzYW5kbyBvIGFyZ3VtZW50byBga2V5YCwgc2VtIHRlcm1vIGRlIGFqdXN0ZS4KCmBgYHtyfQojIGFqdXN0YW5kbyBhIGZ1bsOnw6NvIGRlIGRldGVjw6fDo28gcGFyYSB1bWEgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIGRlIDIwLCAxNSwgMTAgZSA1IG1ldHJvcwojIGRzaXRhbmNpYXMgZGUgdHJ1bmNhbWVudG8KZGlzdF90cnVuY2FtZW50byA8LSBsaXN0KAogIGAyMCBtZXRyb3NgID0gMjAsIAogIGAxNSBtZXRyb3NgID0gMTUsIAogIGAxMCBtZXRyb3NgID0gMTAsCiAgYDUgbWV0cm9zYCA9IDUKKQoKIyBLZXkgZnVuY3Rpb24gLSBIYWxmLW5vcm1hbCAKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faG4gPC0gcHVycnI6Om1hcCgKICBkaXN0X3RydW5jYW1lbnRvLAogIFwoLngpIGFqdXN0ZV9tb2RlbG9zX2Rpc3RhbmNlX2huKAogICAgY3V0aWFfcGFybmFfc2VycmFfcGFyZG8sIAogICAgdHJ1bmNhbWVudG8gPSAueAogICkKICApCmBgYAoKYGBge3J9CmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2huCmBgYAoKIyMjIyAqSGF6YXJkLVJhdGUqIHNlbSB0ZXJtb3MgZGUgYWp1c3RlIGUgY29tIHRlcm1vcyBkZSBhanVzdGUgQ29zc2VubyBlIFBvbGlub21pYWwgZGUgSGVybWl0ZQoKQWp1c3RhbmRvIHVtIG1vZGVsbyBhbyBkYWRvcyBkYSBjdXRpYSAqRGFzeXByb2N0YSBjcm9jb25vdGEqLCBjb25maWd1cmFuZG8gdW1hIGRpc3TDom5jaWEgbGltaXRlIGRlIDIwbSBlIHVzYW5kbyAqSGF6YXJkIHJhdGUqIGNvbW8gKmtleSBmdW5jdGlvbiogdXNhbmRvIG8gYXJndW1lbnRvIGBrZXlgLgoKYGBge3J9CiMgYWp1c3RhbmRvIGEgZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBwYXJhIHVtYSBkaXN0YW5jaWEgZGUgdHJ1bmNhbWVudG8gZGUgMjAsIDE1LCAxMCBlIDUgbWV0cm9zCiMgS2V5IGZ1bmN0aW9uIC0gSGF6YXJkLXJhdGUKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faHIgPC0gcHVycnI6Om1hcCgKICBkaXN0X3RydW5jYW1lbnRvLAogIFwoLngpIGFqdXN0ZV9tb2RlbG9zX2Rpc3RhbmNlX2hyKAogICAgY3V0aWFfcGFybmFfc2VycmFfcGFyZG8sIAogICAgdHJ1bmNhbWVudG8gPSAueAogICkKICApCmBgYAoKIyMjIyAqVW5pZm9ybSogc2VtIHRlcm1vcyBkZSBhanVzdGUgZSBjb20gdGVybW9zIGRlIGFqdXN0ZSBDb3NzZW5vIGUgUG9saW5vbWlhbCBkZSBIZXJtaXRlCgpBanVzdGFuZG8gdW0gbW9kZWxvIGFvIGRhZG9zIGRhcyBjdXRpYXMgKkRhc3lwcm9jdGEgY3JvY29ub3RhKiwgY29uZmlndXJhbmRvIHVtYSBkaXN0w6JuY2lhIGxpbWl0ZSBkZSAyMG0gZSB1c2FuZG8gKlVuaWZvcm0qIGNvbW8gKmtleSBmdW5jdGlvbiogdXNhbmRvIG8gYXJndW1lbnRvIGBrZXlgLCBzZW0gdGVybW8gZGUgYWp1c3RlLgoKYGBge3J9CiMgYWp1c3RhbmRvIGEgZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBwYXJhIHVtYSBkaXN0YW5jaWEgZGUgdHJ1bmNhbWVudG8gZGUgMjAsIDE1LCAxMCBlIDUgbWV0cm9zCiMgS2V5IGZ1bmN0aW9uIC0gVW5pZm9ybQpjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb191bmlmIDwtIHB1cnJyOjptYXAoCiAgZGlzdF90cnVuY2FtZW50bywKICBcKC54KSBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV91bmlmKAogICAgY3V0aWFfcGFybmFfc2VycmFfcGFyZG8sIAogICAgdHJ1bmNhbWVudG8gPSAueAogICkKKQpgYGAKCiMjIyMjIyBTZWxlw6fDo28gZGUgbW9kZWxvcwoKYGBge3J9CnN1bW1hcml6ZV9kc19tb2RlbHMoCiAgY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faG4kYDIwIG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2huJGAyMCBtZXRyb3NgJENvc3Nlbm8sCiAgY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faG4kYDIwIG1ldHJvc2AkYEhlcm1pdGUgcG9saW5vbWlhbGAsCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2hyJGAyMCBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb19ociRgMjAgbWV0cm9zYCRDb3NzZW5vLApjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb19ociRgMjAgbWV0cm9zYCRgUG9saW5vbWlhbCBzaW1wbGVzYCwKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9fdW5pZiRgMjAgbWV0cm9zYCRDb3NzZW5vLApjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb191bmlmJGAyMCBtZXRyb3NgJGBQb2xpbm9taWFsIHNpbXBsZXNgCikKYGBgCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb19obiRgMTUgbWV0cm9zYCRgU2VtIHRlcm1vYCwKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faG4kYDE1IG1ldHJvc2AkQ29zc2VubywKICBjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb19obiRgMTUgbWV0cm9zYCRgSGVybWl0ZSBwb2xpbm9taWFsYCwKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faHIkYDE1IG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2hyJGAxNSBtZXRyb3NgJENvc3Nlbm8sCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2hyJGAxNSBtZXRyb3NgJGBQb2xpbm9taWFsIHNpbXBsZXNgLApjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb191bmlmJGAxNSBtZXRyb3NgJENvc3Nlbm8sCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX3VuaWYkYDE1IG1ldHJvc2AkYFBvbGlub21pYWwgc2ltcGxlc2AKKQpgYGAKCmBgYHtyfQpzdW1tYXJpemVfZHNfbW9kZWxzKAogIGN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2huJGAxMCBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb19obiRgMTAgbWV0cm9zYCRDb3NzZW5vLAogIGN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2huJGAxMCBtZXRyb3NgJGBIZXJtaXRlIHBvbGlub21pYWxgLApjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb19ociRgMTAgbWV0cm9zYCRgU2VtIHRlcm1vYCwKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faHIkYDEwIG1ldHJvc2AkQ29zc2VubywKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faHIkYDEwIG1ldHJvc2AkYFBvbGlub21pYWwgc2ltcGxlc2AsCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX3VuaWYkYDEwIG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX3VuaWYkYDEwIG1ldHJvc2AkQ29zc2VubywKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9fdW5pZiRgMTAgbWV0cm9zYCRgUG9saW5vbWlhbCBzaW1wbGVzYAopCmBgYAoKYGBge3J9CnN1bW1hcml6ZV9kc19tb2RlbHMoCiAgY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faG4kYDUgbWV0cm9zYCRgU2VtIHRlcm1vYCwKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faG4kYDUgbWV0cm9zYCRDb3NzZW5vLAogIGN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2huJGA1IG1ldHJvc2AkYEhlcm1pdGUgcG9saW5vbWlhbGAsCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2hyJGA1IG1ldHJvc2AkYFNlbSB0ZXJtb2AsCmN1dGlhX3Bhcm5hX3NlcnJhX3BhcmRvX2hyJGA1IG1ldHJvc2AkQ29zc2VubywKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9faHIkYDUgbWV0cm9zYCRgUG9saW5vbWlhbCBzaW1wbGVzYCwKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9fdW5pZiRgNSBtZXRyb3NgJGBTZW0gdGVybW9gLApjdXRpYV9wYXJuYV9zZXJyYV9wYXJkb191bmlmJGA1IG1ldHJvc2AkQ29zc2VubywKY3V0aWFfcGFybmFfc2VycmFfcGFyZG9fdW5pZiRgNSBtZXRyb3NgJGBQb2xpbm9taWFsIHNpbXBsZXNgCikKYGBgCgojIyMjIyBUZW50YXRpdmEgZGUgZmF6ZXIgYSBzZWxlw6fDoyBvZGUgbW9kZWxvcyB1c2FuZG8gcHVycnIgLSB0ZW50YXIgYW5pbmhhciBtYWlzIHVtIG1hcAoKYGBge3J9CnB1cnJyOjptYXBfZGYoCiAgbGlzdCgKICAgIGN1dGlhX2VzZWNfdGVycmFfbWVpb19obiRgMjAgbWV0cm9zYCwKICAgIGN1dGlhX2VzZWNfdGVycmFfbWVpb19ociRgMjAgbWV0cm9zYAogICksCiAgXCgueCkgcHVycnI6Om1hcF9kZigueCwgXCgueSkgc3VtbWFyaXplX2RzX21vZGVscygueSkpCikKCnB1cnJyOjptYXBfZGYoCiAgY3V0aWFfZXNlY190ZXJyYV9tZWlvX2huJGAxNSBtZXRyb3NgLAogIFwoLngpIHN1bW1hcml6ZV9kc19tb2RlbHMoLngpCikKCnB1cnJyOjptYXBfZGYoCiAgY3V0aWFfZXNlY190ZXJyYV9tZWlvX2huJGAxMCBtZXRyb3NgLAogIFwoLngpIHN1bW1hcml6ZV9kc19tb2RlbHMoLngpCikKCnB1cnJyOjptYXBfZGYoCiAgY3V0aWFfZXNlY190ZXJyYV9tZWlvX2huJGA1IG1ldHJvc2AsCiAgXCgueCkgc3VtbWFyaXplX2RzX21vZGVscygueCkKKQpgYGAKCmBgYHtyfQoKYGBgCgojIFByaW1laXJhIGVzcMOpY2llIHBhcmEgZGFkb3MgY29tIHJlcGV0acOnw6NvCgojIyAqU2FndWludXMgbWlkYXMqIG5vICoqUGFybmEgTW9udGFuaGFzIGRvIFR1bXVjdW1hcXVlKioKCiFbRm9udGU6IGRhdHVvcGluaW9uLmNvbV0oaHR0cHM6Ly9leHRlcm5hbC1jb250ZW50LmR1Y2tkdWNrZ28uY29tL2l1Lz91PWh0dHBzJTNBJTJGJTJGdHNlNC5tbS5iaW5nLm5ldCUyRnRoJTNGaWQlM0RPSVAuTUtYS1Q5bE5PVHNwbm9jUzlxcGdKQUhhRk8lMjZwaWQlM0RBcGkmZj0xJmlwdD1iYWFjZGVlZmZmMjBkMmNjNzlkMWNjN2JlYmE3NWJiYjg1NTQ2YzRiNTNhNGJhMzMwNWY0Y2NhMmUxZjJlNTkyJmlwbz1pbWFnZXMpCgojIyMgQ2FycmVnYXIgZGFkb3MKCmBgYHtyfQpzYWd1aV9tb250X3R1bXVjIDwtIHRyYW5zZm9ybWFyX3BhcmFfZGlzdGFuY2VSX2NvdmFyaWF2ZWlzKCkgfD4gCiAgZmlsdGVyKAogICAgUmVnaW9uLkxhYmVsID09ICJQYXJuYSBNb250YW5oYXMgZG8gVHVtdWN1bWFxdWUiLAogICAgc3BfbmFtZSA9PSAiU2FndWludXMgbWlkYXMiCiAgKSB8PiAKICBkcm9wX25hKGRpc3RhbmNlKQpgYGAKCiMjIyBEaXN0cmlidWnDp8OjbyBkYXMgZGlzdMOibmNpYXMgcGVycGVuZGljdWxhcmVzCgpgYGB7cn0Kc2FndWlfbW9udF90dW11YyB8PiAKICBwbG90YXJfZGlzdHJpYnVpY2FvX2Rpc3RhbmNpYV9pbnRlcmF0aXZvKCkKYGBgCgojIyMgQWp1c3RhbmRvIG1vZGVsbyBkaXN0YW5jZSBjb20gZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBIYWxmLU5vcm1hbCBlIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byAxMAoKYGBge3J9CnNhZ3VpX21vbnRfdHVtdWNfaG4gPC0gc2FndWlfbW9udF90dW11YyB8PiAKICBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9obihsaXN0YV90ZXJtb3NfYWp1c3RlID0gdHJ1bmNhbWVudG8gPSAxMCkKYGBgCgojIyMgQWp1c3RhbmRvIG1vZGVsbyBkaXN0YW5jZSBjb20gZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBIYXphcmQtcmF0ZSBlIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byAxMAoKYGBge3J9CnNhZ3VpX21vbnRfdHVtdWNfaHIgPC0gc2FndWlfbW9udF90dW11YyB8PiAKICBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9ocih0cnVuY2FtZW50byA9IDEwKQpgYGAKCiMjIyBQbG90IGRvcyBtb2RlbG9zCgpgYGB7cn0Kc2FndWlfbW9udF90dW11Y19obiB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgpgYGB7cn0Kc2FndWlfbW9udF90dW11Y19ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgojIyMgU2VsZcOnw6NvIGRlIG1vZGVsb3MKCmBgYHtyfQpzdW1tYXJpemVfZHNfbW9kZWxzKAogIHNhZ3VpX21vbnRfdHVtdWNfaG4kYFNlbSB0ZXJtb2AsCiAgc2FndWlfbW9udF90dW11Y19obiRDb3NzZW5vLAogIHNhZ3VpX21vbnRfdHVtdWNfaG4kYEhlcm1pdGUgcG9saW5vbWlhbGAsCiAgc2FndWlfbW9udF90dW11Y19ociRgU2VtIHRlcm1vYCwKICBzYWd1aV9tb250X3R1bXVjX2hyJENvc3Nlbm8sCiAgc2FndWlfbW9udF90dW11Y19ociRgUG9saW5vbWlhbCBzaW1wbGVzYAopCmBgYAoKIyMjIFRlc3RlIGRlIGJvbmRhZGUgZGUgYWp1c3RlCgpgYGB7cn0Kc2FndWlfbW9udF90dW11Y19obiB8PiAKICBwdXJycjo6bWFwKFwoLngpIGdvZl9kcyhtb2RlbCA9IC54KSkKYGBgCgpgYGB7cn0Kc2FndWlfbW9udF90dW11Y19ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIGdvZl9kcyhtb2RlbCA9IC54KSkKYGBgCgojIyMgRXN0aW1hbmRvIGEgYWJ1bmRhbmNpYQoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgYXJlYSBjb2JlcnRhIHBlbG8gZXNmb3LDp28gYW1vc3RyYWwsIGVzZm9yw6dvIGFtb3N0cmFsIGVtIG1ldHJvcywgbsO6bWVybyBkZSBkZXRlY8Onw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zIChlYSksIHRheGEgZGUgZW5jb250cm8sIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgdGF4YSBkZSBlbmNvbnRybyAgCnNhZ3VpX21vbnRfdHVtdWNfaG4kYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJHN1bW1hcnlbMTo5XQpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIHRyaWxoYXMgb3UgZXN0YcOnw7VlcyBhbW9zdHJhaXMsIGVzZm9yw6dvIHRvdGFsIGVtIGNhZGEgdHJpbGhhLCBhYnVuZMOibmNpYSBlc3RpbWFkYSBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgbsO6bWVybyBkZSBkZXRlY8Onw7VlcyBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgw6FyZWEgdG90YWwgYW1vc3RyYWRhCnNhZ3VpX21vbnRfdHVtdWNfaG4kYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJE5oYXQuYnkuc2FtcGxlWzE6OF0KYGBgCgpgYGB7cn0KIyB0b3RhbCwgZGVuc2lkYWRlIGVzdGltYWRhLCBlcnJvIHBhZHLDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpzYWd1aV9tb250X3R1bXVjX2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRECgpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIGFyZWEgY29iZXJ0YSBwZWxvIGVzZm9yw6dvIGFtb3N0cmFsLCBlc2ZvcsOnbyBhbW9zdHJhbCBlbSBtZXRyb3MsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMsIG7Dum1lcm8gZGUgdHJhbnNlY3RvcyAoZWEpLCB0YXhhIGRlIGVuY29udHJvLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIHRheGEgZGUgZW5jb250cm8gIApzYWd1aV9tb250X3R1bXVjX2hyJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRzdW1tYXJ5WzE6OV0KYGBgCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCB0cmlsaGFzIG91IGVzdGHDp8O1ZXMgYW1vc3RyYWlzLCBlc2ZvcsOnbyB0b3RhbCBlbSBjYWRhIHRyaWxoYSwgYWJ1bmTDom5jaWEgZXN0aW1hZGEgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIMOhcmVhIHRvdGFsIGFtb3N0cmFkYQpzYWd1aV9tb250X3R1bXVjX2hyJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyROaGF0LmJ5LnNhbXBsZVsxOjhdCmBgYAoKYGBge3J9CiMgdG90YWwsIGRlbnNpZGFkZSBlc3RpbWFkYSwgZXJybyBwYWRyw6NvIGRhIGRlbnNpZGFkZSBkZXN0aW1hZGEsIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgaW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EgaW5mZXJpb3IgZSBzdXBlcmlvciBkbyBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvLCBncnVhcyBkZSBsaWJlcmRhZGUKc2FndWlfbW9udF90dW11Y19ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkRApgYGAKCiMgU2VndW5kYSBlc3DDqWNpZSBwYXJhIGRhZG9zIGNvbSByZXBldGnDp8OjbwoKIyMgKk15b3Byb2N0YSBwcmF0dGkqIG5hICoqUmVzZXggQWx0byBUYXJhdWFjw6EqKgoKIVtGb250ZTogem9vY2hhdC5jb21dKGh0dHBzOi8vZXh0ZXJuYWwtY29udGVudC5kdWNrZHVja2dvLmNvbS9pdS8/dT1odHRwcyUyNTNBJTI1MkYlMjUyRnRzZTMubW0uYmluZy5uZXQlMjUyRnRoJTI1M0ZpZCUyNTNET0lQLmhxQ051U1pTWVpZZkZfaFR1b0ZsV0FIYUU4JTI1MjZwaWQlMjUzREFwaSZmPTEmaXB0PTY3MDhjMDhkZTM4MGZmZjM3MjY3Yzg4NTYzYzQ5NTg2NTNkZTZiYzg4YzQ0OTc5YjIwZjJmZDdmZmNiYmFkNGEmaXBvPWltYWdlcykKCiMjIyBDYXJyZWdhciBkYWRvcwoKYGBge3J9CmN1dGlhX2FsdG9fdGFyYXUgPC0gdHJhbnNmb3JtYXJfcGFyYV9kaXN0YW5jZVJfY292YXJpYXZlaXMoKSB8PiAKICBmaWx0ZXIoCiAgICBSZWdpb24uTGFiZWwgPT0gIlJlc2V4IEFsdG8gVGFyYXVhY8OhIiwKICAgIHNwX25hbWUgPT0gIk15b3Byb2N0YSBwcmF0dGkiCiAgKSB8PiAKICBkcm9wX25hKGRpc3RhbmNlKQpgYGAKCiMjIyBEaXN0cmlidWnDp8OjbyBkYXMgZGlzdMOibmNpYXMgcGVycGVuZGljdWxhcmVzCgpgYGB7cn0KY3V0aWFfYWx0b190YXJhdSB8PiAKICBwbG90YXJfZGlzdHJpYnVpY2FvX2Rpc3RhbmNpYV9pbnRlcmF0aXZvKCkKYGBgCgojIyMgQWp1c3RhbmRvIG1vZGVsbyBkaXN0YW5jZSBjb20gZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBIYWxmLU5vcm1hbCBlIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byAxMAoKYGBge3J9CmN1dGlhX2FsdG9fdGFyYXVfaG4gPC0gY3V0aWFfYWx0b190YXJhdSB8PiAKICBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9obih0cnVuY2FtZW50byA9IDEwKQpgYGAKCiMjIyBBanVzdGFuZG8gbW9kZWxvIGRpc3RhbmNlIGNvbSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIEhhemFyZC1yYXRlIGUgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIDEwCgpgYGB7cn0KY3V0aWFfYWx0b190YXJhdV9ociA8LSBjdXRpYV9hbHRvX3RhcmF1IHw+IAogIGFqdXN0ZV9tb2RlbG9zX2Rpc3RhbmNlX2hyKHRydW5jYW1lbnRvID0gMTApCmBgYAoKIyMjIFBsb3QgZG9zIG1vZGVsb3MKCmBgYHtyfQpjdXRpYV9hbHRvX3RhcmF1X2huIHw+IAogIHB1cnJyOjptYXAoXCgueCkgcGxvdCgueCkpIApgYGAKCmBgYHtyfQpjdXRpYV9hbHRvX3RhcmF1X2hyIHw+IAogIHB1cnJyOjptYXAoXCgueCkgcGxvdCgueCkpIApgYGAKCiMjIyBTZWxlw6fDo28gZGUgbW9kZWxvcwoKYGBge3J9CnN1bW1hcml6ZV9kc19tb2RlbHMoCiAgY3V0aWFfYWx0b190YXJhdV9obiRgU2VtIHRlcm1vYCwKICBjdXRpYV9hbHRvX3RhcmF1X2huJENvc3Nlbm8sCiAgY3V0aWFfYWx0b190YXJhdV9obiRgSGVybWl0ZSBwb2xpbm9taWFsYCwKICBjdXRpYV9hbHRvX3RhcmF1X2hyJGBTZW0gdGVybW9gLAogIGN1dGlhX2FsdG9fdGFyYXVfaHIkQ29zc2VubywKICBjdXRpYV9hbHRvX3RhcmF1X2hyJGBQb2xpbm9taWFsIHNpbXBsZXNgCikKYGBgCgojIyMgVGVzdGUgZGUgYm9uZGFkZSBkZSBhanVzdGUKCmBgYHtyfQpjdXRpYV9hbHRvX3RhcmF1X2huIHw+IAogIHB1cnJyOjptYXAoXCgueCkgZ29mX2RzKG1vZGVsID0gLngpKQpgYGAKCmBgYHtyfQpjdXRpYV9hbHRvX3RhcmF1X2hyIHw+IAogIHB1cnJyOjptYXAoXCgueCkgZ29mX2RzKG1vZGVsID0gLngpKQpgYGAKCiMjIyBFc3RpbWFuZG8gYSBhYnVuZGFuY2lhCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCBhcmVhIGNvYmVydGEgcGVsbyBlc2ZvcsOnbyBhbW9zdHJhbCwgZXNmb3LDp28gYW1vc3RyYWwgZW0gbWV0cm9zLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzLCBuw7ptZXJvIGRlIHRyYW5zZWN0b3MgKGVhKSwgdGF4YSBkZSBlbmNvbnRybywgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSB0YXhhIGRlIGVuY29udHJvICAKY3V0aWFfYWx0b190YXJhdV9obiRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkc3VtbWFyeVsxOjldCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgdHJpbGhhcyBvdSBlc3Rhw6fDtWVzIGFtb3N0cmFpcywgZXNmb3LDp28gdG90YWwgZW0gY2FkYSB0cmlsaGEsIGFidW5kw6JuY2lhIGVzdGltYWRhIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCDDoXJlYSB0b3RhbCBhbW9zdHJhZGEKY3V0aWFfYWx0b190YXJhdV9obiRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkTmhhdC5ieS5zYW1wbGVbMTo4XQpgYGAKCmBgYHtyfQojIHRvdGFsLCBkZW5zaWRhZGUgZXN0aW1hZGEsIGVycm8gcGFkcsOjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIGRlbnNpZGFkZSBkZXN0aW1hZGEsIGludGVydmFsbyBkZSBjb25maWFuw6dhIGluZmVyaW9yIGUgc3VwZXJpb3IgZG8gY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbywgZ3J1YXMgZGUgbGliZXJkYWRlCmN1dGlhX2FsdG9fdGFyYXVfaG4kYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJEQKCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgYXJlYSBjb2JlcnRhIHBlbG8gZXNmb3LDp28gYW1vc3RyYWwsIGVzZm9yw6dvIGFtb3N0cmFsIGVtIG1ldHJvcywgbsO6bWVybyBkZSBkZXRlY8Onw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zIChlYSksIHRheGEgZGUgZW5jb250cm8sIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgdGF4YSBkZSBlbmNvbnRybyAgCmN1dGlhX2FsdG9fdGFyYXVfaHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJHN1bW1hcnlbMTo5XQpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIHRyaWxoYXMgb3UgZXN0YcOnw7VlcyBhbW9zdHJhaXMsIGVzZm9yw6dvIHRvdGFsIGVtIGNhZGEgdHJpbGhhLCBhYnVuZMOibmNpYSBlc3RpbWFkYSBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgbsO6bWVybyBkZSBkZXRlY8Onw7VlcyBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgw6FyZWEgdG90YWwgYW1vc3RyYWRhCmN1dGlhX2FsdG9fdGFyYXVfaHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJE5oYXQuYnkuc2FtcGxlWzE6OF0KYGBgCgpgYGB7cn0KIyB0b3RhbCwgZGVuc2lkYWRlIGVzdGltYWRhLCBlcnJvIHBhZHLDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpjdXRpYV9hbHRvX3RhcmF1X2hyJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRECgpgYGAKCiMgVGVyY2VpcmEgZXNww6ljaWUgcGFyYSBkYWRvcyBjb20gcmVwZXRpw6fDo28KCiMjICpMYWdvdGhyaXggY2FuYSogbmEgKipSZWJpbyBkbyBKYXJ1KioKCiFbRm9udGU6IHpvb2NoYXQuY29tXShodHRwczovL2V4dGVybmFsLWNvbnRlbnQuZHVja2R1Y2tnby5jb20vaXUvP3U9aHR0cHMlM0ElMkYlMkZ0c2UxLm1tLmJpbmcubmV0JTJGdGglM0ZpZCUzRE9JUC53Tkt4UzhlX0NHTzg5VE9Pb1R5LXl3SGFFOCUyNnBpZCUzREFwaSZmPTEmaXB0PTQzMzA2ZDc0YWU3ZjA1Y2YwYzk4Yjk4YmZhYzdkMTEzZmJiNDAzMWMyNjdlNWVmYWU2MTZmYjk5OWRjNjRkZDAmaXBvPWltYWdlcykKCiMjIyBDYXJyZWdhciBkYWRvcwoKYGBge3J9Cm1hY2Fjb19qYXJ1IDwtIHRyYW5zZm9ybWFyX3BhcmFfZGlzdGFuY2VSX2NvdmFyaWF2ZWlzKCkgfD4gCiAgZmlsdGVyKAogICAgUmVnaW9uLkxhYmVsID09ICJSZWJpbyBkbyBKYXJ1IiwKICAgIHNwX25hbWUgPT0gIkxhZ290aHJpeCBjYW5hIgogICkgfD4gCiAgZHJvcF9uYShkaXN0YW5jZSkKYGBgCgojIyMgRGlzdHJpYnVpw6fDo28gZGFzIGRpc3TDom5jaWFzIHBlcnBlbmRpY3VsYXJlcwoKYGBge3J9Cm1hY2Fjb19qYXJ1IHw+IAogIHBsb3Rhcl9kaXN0cmlidWljYW9fZGlzdGFuY2lhX2ludGVyYXRpdm8oKQpgYGAKCiMjIyBBanVzdGFuZG8gbW9kZWxvIGRpc3RhbmNlIGNvbSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIEhhbGYtTm9ybWFsIGUgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIDIwCgpgYGB7cn0KbWFjYWNvX2phcnVfaG4gPC0gbWFjYWNvX2phcnUgfD4gCiAgYWp1c3RlX21vZGVsb3NfZGlzdGFuY2VfaG4odHJ1bmNhbWVudG8gPSAyMCkKYGBgCgojIyMgQWp1c3RhbmRvIG1vZGVsbyBkaXN0YW5jZSBjb20gZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBIYXphcmQtcmF0ZSBlIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byAyMAoKYGBge3J9Cm1hY2Fjb19qYXJ1X2hyIDwtIG1hY2Fjb19qYXJ1IHw+IAogIGFqdXN0ZV9tb2RlbG9zX2Rpc3RhbmNlX2hyKHRydW5jYW1lbnRvID0gMjApCmBgYAoKIyMjIFBsb3QgZG9zIG1vZGVsb3MKCmBgYHtyfQptYWNhY29famFydV9obiB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgpgYGB7cn0KbWFjYWNvX2phcnVfaHIgfD4gCiAgcHVycnI6Om1hcChcKC54KSBwbG90KC54KSkgCmBgYAoKIyMjIFNlbGXDp8OjbyBkZSBtb2RlbG9zCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBtYWNhY29famFydV9obiRgU2VtIHRlcm1vYCwKICBtYWNhY29famFydV9obiRDb3NzZW5vLAogIG1hY2Fjb19qYXJ1X2huJGBIZXJtaXRlIHBvbGlub21pYWxgLAogIG1hY2Fjb19qYXJ1X2hyJGBTZW0gdGVybW9gLAogIG1hY2Fjb19qYXJ1X2hyJENvc3Nlbm8sCiAgbWFjYWNvX2phcnVfaHIkYFBvbGlub21pYWwgc2ltcGxlc2AKKQpgYGAKCiMjIyBUZXN0ZSBkZSBib25kYWRlIGRlIGFqdXN0ZQoKYGBge3J9Cm1hY2Fjb19qYXJ1X2huIHw+IAogIHB1cnJyOjptYXAoXCgueCkgZ29mX2RzKG1vZGVsID0gLngpKQpgYGAKCmBgYHtyfQptYWNhY29famFydV9ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIGdvZl9kcyhtb2RlbCA9IC54KSkKYGBgCgojIyMgRXN0aW1hbmRvIGEgYWJ1bmRhbmNpYQoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgYXJlYSBjb2JlcnRhIHBlbG8gZXNmb3LDp28gYW1vc3RyYWwsIGVzZm9yw6dvIGFtb3N0cmFsIGVtIG1ldHJvcywgbsO6bWVybyBkZSBkZXRlY8Onw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zIChlYSksIHRheGEgZGUgZW5jb250cm8sIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgdGF4YSBkZSBlbmNvbnRybyAgCm1hY2Fjb19qYXJ1X2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRzdW1tYXJ5WzE6OV0KYGBgCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCB0cmlsaGFzIG91IGVzdGHDp8O1ZXMgYW1vc3RyYWlzLCBlc2ZvcsOnbyB0b3RhbCBlbSBjYWRhIHRyaWxoYSwgYWJ1bmTDom5jaWEgZXN0aW1hZGEgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIMOhcmVhIHRvdGFsIGFtb3N0cmFkYQptYWNhY29famFydV9obiRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkTmhhdC5ieS5zYW1wbGVbMTo4XQpgYGAKCmBgYHtyfQojIHRvdGFsLCBkZW5zaWRhZGUgZXN0aW1hZGEsIGVycm8gcGFkcsOjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIGRlbnNpZGFkZSBkZXN0aW1hZGEsIGludGVydmFsbyBkZSBjb25maWFuw6dhIGluZmVyaW9yIGUgc3VwZXJpb3IgZG8gY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbywgZ3J1YXMgZGUgbGliZXJkYWRlCm1hY2Fjb19qYXJ1X2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRECgpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIGFyZWEgY29iZXJ0YSBwZWxvIGVzZm9yw6dvIGFtb3N0cmFsLCBlc2ZvcsOnbyBhbW9zdHJhbCBlbSBtZXRyb3MsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMsIG7Dum1lcm8gZGUgdHJhbnNlY3RvcyAoZWEpLCB0YXhhIGRlIGVuY29udHJvLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIHRheGEgZGUgZW5jb250cm8gIAptYWNhY29famFydV9ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkc3VtbWFyeVsxOjldCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgdHJpbGhhcyBvdSBlc3Rhw6fDtWVzIGFtb3N0cmFpcywgZXNmb3LDp28gdG90YWwgZW0gY2FkYSB0cmlsaGEsIGFidW5kw6JuY2lhIGVzdGltYWRhIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCDDoXJlYSB0b3RhbCBhbW9zdHJhZGEKbWFjYWNvX2phcnVfaHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJE5oYXQuYnkuc2FtcGxlWzE6OF0KYGBgCgpgYGB7cn0KIyB0b3RhbCwgZGVuc2lkYWRlIGVzdGltYWRhLCBlcnJvIHBhZHLDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQptYWNhY29famFydV9ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkRAoKYGBgCgojIFF1YXJ0YSBlc3DDqWNpZSBwYXJhIGRhZG9zIGNvbSByZXBldGnDp8OjbwoKIyMgKk1hemFtYSBhbWVyaWNhbmEqIG5hICoqUmVzZXggVGFwYWpvcy1BcmFwaXVucyoqCgohW0ZvbnRlOiB6b29jaGF0LmNvbV0oaHR0cHM6Ly9leHRlcm5hbC1jb250ZW50LmR1Y2tkdWNrZ28uY29tL2l1Lz91PWh0dHBzJTNBJTJGJTJGdHNlMi5tbS5iaW5nLm5ldCUyRnRoJTNGaWQlM0RPSVAuVjdNMG1DSWU1YkZ0Sk12NE8wNGpnQUhhRTglMjZwaWQlM0RBcGkmZj0xJmlwdD04MWYyN2VkM2UyODgyYmFkYmE2MTlkMTJjNzk4ZjJjMjljODk2YmQ3MGNiNzFmNmRhOTE5MDJjMTNkZmJiMDZmJmlwbz1pbWFnZXMpCgojIyMgQ2FycmVnYXIgZGFkb3MKCmBgYHtyfQpjZXJ2b190YXBfYXJhcCA8LSB0cmFuc2Zvcm1hcl9wYXJhX2Rpc3RhbmNlUl9jb3ZhcmlhdmVpcygpIHw+IAogIGZpbHRlcigKICAgIFJlZ2lvbi5MYWJlbCA9PSAiUmVzZXggVGFwYWpvcy1BcmFwaXVucyIsCiAgICBzcF9uYW1lID09ICJNYXphbWEgYW1lcmljYW5hIgogICkgfD4gCiAgZHJvcF9uYShkaXN0YW5jZSkKYGBgCgojIyMgRGlzdHJpYnVpw6fDo28gZGFzIGRpc3TDom5jaWFzIHBlcnBlbmRpY3VsYXJlcwoKYGBge3J9CmNlcnZvX3RhcF9hcmFwIHw+IAogIHBsb3Rhcl9kaXN0cmlidWljYW9fZGlzdGFuY2lhX2ludGVyYXRpdm8oKQpgYGAKCiMjIyBBanVzdGFuZG8gbW9kZWxvIGRpc3RhbmNlIGNvbSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIEhhbGYtTm9ybWFsIGUgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIDEzCgpgYGB7cn0KY2Vydm9fdGFwX2FyYXBfaG4gPC0gY2Vydm9fdGFwX2FyYXAgfD4gCiAgYWp1c3RlX21vZGVsb3NfZGlzdGFuY2VfaG4odHJ1bmNhbWVudG8gPSAxMykKYGBgCgojIyMgQWp1c3RhbmRvIG1vZGVsbyBkaXN0YW5jZSBjb20gZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBIYXphcmQtcmF0ZSBlIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byAxMwoKYGBge3J9CmNlcnZvX3RhcF9hcmFwX2hyIDwtIGNlcnZvX3RhcF9hcmFwIHw+IAogIGFqdXN0ZV9tb2RlbG9zX2Rpc3RhbmNlX2hyKHRydW5jYW1lbnRvID0gMTMpCmBgYAoKIyMjIFBsb3QgZG9zIG1vZGVsb3MKCmBgYHtyfQpjZXJ2b190YXBfYXJhcF9obiB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgpgYGB7cn0KY2Vydm9fdGFwX2FyYXBfaHIgfD4gCiAgcHVycnI6Om1hcChcKC54KSBwbG90KC54KSkgCmBgYAoKIyMjIFNlbGXDp8OjbyBkZSBtb2RlbG9zCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBjZXJ2b190YXBfYXJhcF9obiRgU2VtIHRlcm1vYCwKICBjZXJ2b190YXBfYXJhcF9obiRDb3NzZW5vLAogIGNlcnZvX3RhcF9hcmFwX2huJGBIZXJtaXRlIHBvbGlub21pYWxgLAogIGNlcnZvX3RhcF9hcmFwX2hyJGBTZW0gdGVybW9gLAogIGNlcnZvX3RhcF9hcmFwX2hyJENvc3Nlbm8sCiAgY2Vydm9fdGFwX2FyYXBfaHIkYFBvbGlub21pYWwgc2ltcGxlc2AKKQpgYGAKCiMjIyBUZXN0ZSBkZSBib25kYWRlIGRlIGFqdXN0ZQoKYGBge3J9CmNlcnZvX3RhcF9hcmFwX2huIHw+IAogIHB1cnJyOjptYXAoXCgueCkgZ29mX2RzKG1vZGVsID0gLngpKQpgYGAKCmBgYHtyfQpjZXJ2b190YXBfYXJhcF9ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIGdvZl9kcyhtb2RlbCA9IC54KSkKYGBgCgojIyMgRXN0aW1hbmRvIGEgYWJ1bmRhbmNpYQoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgYXJlYSBjb2JlcnRhIHBlbG8gZXNmb3LDp28gYW1vc3RyYWwsIGVzZm9yw6dvIGFtb3N0cmFsIGVtIG1ldHJvcywgbsO6bWVybyBkZSBkZXRlY8Onw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zIChlYSksIHRheGEgZGUgZW5jb250cm8sIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgdGF4YSBkZSBlbmNvbnRybyAgCmNlcnZvX3RhcF9hcmFwX2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRzdW1tYXJ5WzE6OV0KYGBgCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCB0cmlsaGFzIG91IGVzdGHDp8O1ZXMgYW1vc3RyYWlzLCBlc2ZvcsOnbyB0b3RhbCBlbSBjYWRhIHRyaWxoYSwgYWJ1bmTDom5jaWEgZXN0aW1hZGEgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIMOhcmVhIHRvdGFsIGFtb3N0cmFkYQpjZXJ2b190YXBfYXJhcF9obiRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkTmhhdC5ieS5zYW1wbGVbMTo4XQpgYGAKCmBgYHtyfQojIHRvdGFsLCBkZW5zaWRhZGUgZXN0aW1hZGEsIGVycm8gcGFkcsOjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIGRlbnNpZGFkZSBkZXN0aW1hZGEsIGludGVydmFsbyBkZSBjb25maWFuw6dhIGluZmVyaW9yIGUgc3VwZXJpb3IgZG8gY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbywgZ3J1YXMgZGUgbGliZXJkYWRlCmNlcnZvX3RhcF9hcmFwX2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRECgpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIGFyZWEgY29iZXJ0YSBwZWxvIGVzZm9yw6dvIGFtb3N0cmFsLCBlc2ZvcsOnbyBhbW9zdHJhbCBlbSBtZXRyb3MsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMsIG7Dum1lcm8gZGUgdHJhbnNlY3RvcyAoZWEpLCB0YXhhIGRlIGVuY29udHJvLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIHRheGEgZGUgZW5jb250cm8gIApjZXJ2b190YXBfYXJhcF9ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkc3VtbWFyeVsxOjldCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgdHJpbGhhcyBvdSBlc3Rhw6fDtWVzIGFtb3N0cmFpcywgZXNmb3LDp28gdG90YWwgZW0gY2FkYSB0cmlsaGEsIGFidW5kw6JuY2lhIGVzdGltYWRhIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCDDoXJlYSB0b3RhbCBhbW9zdHJhZGEKY2Vydm9fdGFwX2FyYXBfaHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJE5oYXQuYnkuc2FtcGxlWzE6OF0KYGBgCgpgYGB7cn0KIyB0b3RhbCwgZGVuc2lkYWRlIGVzdGltYWRhLCBlcnJvIHBhZHLDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpjZXJ2b190YXBfYXJhcF9ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkRAoKYGBgCgojIFF1aW50YSBlc3DDqWNpZSBwYXJhIGRhZG9zIGNvbSByZXBldGnDp8OjbwoKIyMgKlRpbmFtdXMgbWFqb3IqIG5hICoqUGFybmEgTW9udGFuaGFzIGRvIFR1bXVjdW1hcXVlKioKCiFbRm9udGU6IHBpbnRlcmVzdC5jb21dKGh0dHBzOi8vZXh0ZXJuYWwtY29udGVudC5kdWNrZHVja2dvLmNvbS9pdS8/dT1odHRwcyUzQSUyRiUyRnRzZTEubW0uYmluZy5uZXQlMkZ0aCUzRmlkJTNET0lQLjNtRy15VlpxOXZOMGFPSVRCN2x0cGdIYUVyJTI2cGlkJTNEQXBpJmY9MSZpcHQ9YmRlYzM0ZDM5M2JjYWRkZDljZWRjZWRiODFkYWE2NDk2NjgwNjE5ZjEzZDcwNGI2ZDQxOWZmNTE2ZTViNTIxMCZpcG89aW1hZ2VzKQoKIyMjIENhcnJlZ2FyIGRhZG9zCgpgYGB7cn0KaW5hbWJ1X21vbnRfdHVtdWMgPC0gdHJhbnNmb3JtYXJfcGFyYV9kaXN0YW5jZVJfY292YXJpYXZlaXMoKSB8PiAKICBmaWx0ZXIoCiAgICBSZWdpb24uTGFiZWwgPT0gIlBhcm5hIE1vbnRhbmhhcyBkbyBUdW11Y3VtYXF1ZSIsCiAgICBzcF9uYW1lID09ICJUaW5hbXVzIG1ham9yIgogICkgfD4gCiAgZHJvcF9uYShkaXN0YW5jZSkKYGBgCgojIyMgRGlzdHJpYnVpw6fDo28gZGFzIGRpc3TDom5jaWFzIHBlcnBlbmRpY3VsYXJlcwoKYGBge3J9CmluYW1idV9tb250X3R1bXVjIHw+IAogIHBsb3Rhcl9kaXN0cmlidWljYW9fZGlzdGFuY2lhX2ludGVyYXRpdm8oKQpgYGAKCiMjIyBBanVzdGFuZG8gbW9kZWxvIGRpc3RhbmNlIGNvbSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIEhhbGYtTm9ybWFsIGUgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIDE1CgpgYGB7cn0KaW5hbWJ1X21vbnRfdHVtdWNfaG4gPC0gaW5hbWJ1X21vbnRfdHVtdWMgfD4gCiAgYWp1c3RlX21vZGVsb3NfZGlzdGFuY2VfaG4odHJ1bmNhbWVudG8gPSAxNSkKYGBgCgojIyMgQWp1c3RhbmRvIG1vZGVsbyBkaXN0YW5jZSBjb20gZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBIYXphcmQtcmF0ZSBlIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byAxNQoKYGBge3J9CmluYW1idV9tb250X3R1bXVjX2hyIDwtIGluYW1idV9tb250X3R1bXVjIHw+IAogIGFqdXN0ZV9tb2RlbG9zX2Rpc3RhbmNlX2hyKHRydW5jYW1lbnRvID0gMTUpCmBgYAoKIyMjIFBsb3QgZG9zIG1vZGVsb3MKCmBgYHtyfQppbmFtYnVfbW9udF90dW11Y19obiB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgpgYGB7cn0KaW5hbWJ1X21vbnRfdHVtdWNfaHIgfD4gCiAgcHVycnI6Om1hcChcKC54KSBwbG90KC54KSkgCmBgYAoKIyMjIFNlbGXDp8OjbyBkZSBtb2RlbG9zCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBpbmFtYnVfbW9udF90dW11Y19obiRgU2VtIHRlcm1vYCwKICBpbmFtYnVfbW9udF90dW11Y19obiRDb3NzZW5vLAogIGluYW1idV9tb250X3R1bXVjX2huJGBIZXJtaXRlIHBvbGlub21pYWxgLAogIGluYW1idV9tb250X3R1bXVjX2hyJGBTZW0gdGVybW9gLAogIGluYW1idV9tb250X3R1bXVjX2hyJENvc3Nlbm8sCiAgaW5hbWJ1X21vbnRfdHVtdWNfaHIkYFBvbGlub21pYWwgc2ltcGxlc2AKKQpgYGAKCiMjIyBUZXN0ZSBkZSBib25kYWRlIGRlIGFqdXN0ZQoKYGBge3J9CmluYW1idV9tb250X3R1bXVjX2huIHw+IAogIHB1cnJyOjptYXAoXCgueCkgZ29mX2RzKG1vZGVsID0gLngpKQpgYGAKCmBgYHtyfQppbmFtYnVfbW9udF90dW11Y19ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIGdvZl9kcyhtb2RlbCA9IC54KSkKYGBgCgojIyMgRXN0aW1hbmRvIGEgYWJ1bmRhbmNpYQoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgYXJlYSBjb2JlcnRhIHBlbG8gZXNmb3LDp28gYW1vc3RyYWwsIGVzZm9yw6dvIGFtb3N0cmFsIGVtIG1ldHJvcywgbsO6bWVybyBkZSBkZXRlY8Onw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zIChlYSksIHRheGEgZGUgZW5jb250cm8sIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgdGF4YSBkZSBlbmNvbnRybyAgCmluYW1idV9tb250X3R1bXVjX2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRzdW1tYXJ5WzE6OV0KYGBgCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCB0cmlsaGFzIG91IGVzdGHDp8O1ZXMgYW1vc3RyYWlzLCBlc2ZvcsOnbyB0b3RhbCBlbSBjYWRhIHRyaWxoYSwgYWJ1bmTDom5jaWEgZXN0aW1hZGEgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIMOhcmVhIHRvdGFsIGFtb3N0cmFkYQppbmFtYnVfbW9udF90dW11Y19obiRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkTmhhdC5ieS5zYW1wbGVbMTo4XQpgYGAKCmBgYHtyfQojIHRvdGFsLCBkZW5zaWRhZGUgZXN0aW1hZGEsIGVycm8gcGFkcsOjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIGRlbnNpZGFkZSBkZXN0aW1hZGEsIGludGVydmFsbyBkZSBjb25maWFuw6dhIGluZmVyaW9yIGUgc3VwZXJpb3IgZG8gY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbywgZ3J1YXMgZGUgbGliZXJkYWRlCmluYW1idV9tb250X3R1bXVjX2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRECgpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIGFyZWEgY29iZXJ0YSBwZWxvIGVzZm9yw6dvIGFtb3N0cmFsLCBlc2ZvcsOnbyBhbW9zdHJhbCBlbSBtZXRyb3MsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMsIG7Dum1lcm8gZGUgdHJhbnNlY3RvcyAoZWEpLCB0YXhhIGRlIGVuY29udHJvLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIHRheGEgZGUgZW5jb250cm8gIAppbmFtYnVfbW9udF90dW11Y19ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkc3VtbWFyeVsxOjldCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgdHJpbGhhcyBvdSBlc3Rhw6fDtWVzIGFtb3N0cmFpcywgZXNmb3LDp28gdG90YWwgZW0gY2FkYSB0cmlsaGEsIGFidW5kw6JuY2lhIGVzdGltYWRhIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCDDoXJlYSB0b3RhbCBhbW9zdHJhZGEKaW5hbWJ1X21vbnRfdHVtdWNfaHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJE5oYXQuYnkuc2FtcGxlWzE6OF0KYGBgCgpgYGB7cn0KIyB0b3RhbCwgZGVuc2lkYWRlIGVzdGltYWRhLCBlcnJvIHBhZHLDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQppbmFtYnVfbW9udF90dW11Y19ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkRAoKYGBgCgojIFRldG5hdGl2YSBkZSBmaWx0cmFnZW0gZSBzZWxlw6fDo28gZGUgZGFkb3MgcGFyYSBlbGltaW5hciByZXBldGnDp8O1ZXMKCk5hIHByaW1laXJhIHRlbnRhdGl2YSBkZSBhanVzdGUgZG8gbW9kZWxvIGRpc3RhbmNlIHBhcmEgZGFkb3Mgc2VtIHJlcGV0acOnw6NvLCBvcyBkYWRvcyBkYSBjdXRpYSAqRGFzeXByb2N0YSBjcm9jb25vdGEqLCBzZW0gZXN0cmF0aWZpY2HDp8OjbywgcGFyYSBvIFBhcm5hIGRhIFNlcnJhIGRvIFBhcmRvLCBFc2VjIGRhIFRlcnJhIGRvIE1laW8gZSBSZXNleCBSaW96aW5obyBkbyBBbmZyw61zaW8uIEVtIHNlZ3VpZGEsIG9zIGRhZG9zIGRhIG1lc21hIGVzcMOpY2llIHNlcsOjbyBhbmFsaXNhZG9zIHBhcmEgUmVzZXggVGFwYWrDs3MtQXJhcGl1bnMgZXN0cmF0aWZpY2Fkb3MgcG9yIGFuby4KCiMjICpEYXN5cHJvY3RhIGNyb2Nvbm90YSogbmEgKipQYXJuYSBkYSBTZXJyYSBkbyBQYXJkbyoqCgohW0ZvbnRlOiBiaW9saWIuY3pdKGh0dHBzOi8vd3d3LmJpb2xpYi5jei9JTUcvR0FML0JJRy8yMDU4NDkuanBnKQoKIyMjIENhcnJlZ2FyIGRhZG9zCgpgYGB7cn0KZGFzeV9jcm9jX3NlcnJhX3BhcmRvIDwtIHRyYW5zZm9ybWFyX3BhcmFfZGlzdGFuY2VSX2NvdmFyaWF2ZWlzX3NlbV9yZXBldGljYW8oKSB8PiAgIGZpbHRlcigKICAgIFJlZ2lvbi5MYWJlbCA9PSAiUGFybmEgZGEgU2VycmEgZG8gUGFyZG8iLCAKICAgIHNwX25hbWUgPT0gIkRhc3lwcm9jdGEgY3JvY29ub3RhIgogICkgfD4gCiAgZHJvcF9uYShkaXN0YW5jZSkKCmRhc3lfY3JvY19zZXJyYV9wYXJkbwpgYGAKCiMjIyBWZXJpZmljYXIgbyBuw7ptZXJvIGRlIG9ic2VydmHDp8O1ZXMgcG9yIGRhdGEgZGUgYW1vc3RyYWdlbQoKYGBge3J9CnRlc3RlMSA8LSBkYXN5X2Nyb2Nfc2VycmFfcGFyZG8gfD4gCiAgZ3JvdXBfYnkoU2FtcGxlLkxhYmVsLCBzYW1wbGluZ19kYXksIHllYXIsIHNlYXNvbikgfD4gCiAgY291bnQoc2FtcGxpbmdfZGF5KSB8PiAKICB1bmdyb3VwKCkgfD4gCiAgYXJyYW5nZShTYW1wbGUuTGFiZWwsIHNhbXBsaW5nX2RheSkKCnRlc3RlMQpgYGAKCiMjIFZlcmlmaWNhciBhcyBkYXRhcyBjb20gbWFpb3IgbsO6bWVybyBkZSBvYnNlcnZhw6fDtWVzIGVtIGNhZGEgYW5vCnRlbnRhciBnZXJhciB1bWEgbm92YSBjb2x1bmEgdXNhbmRvIHVtYSBjb25kaWNpb25hbCBxdWUgcmVwaXRhIHVtYSDDum5pY2EgZGF0YSBwYXJhIGRhdGFzIHF1ZSBvY29ycmVtIGRlbnRybyBkbyBpbnRlcnZhbG8gYW1vc3RyYWwuIGRlcG9pcyBiYXN0YSBtYW50ZXIgYXMgb2JzZXJ2YcOnw7VlcyDDum5pY2FzIHVzYW5kbyBkaXN0aW5jdCgpCmBgYHtyfQp0ZXN0ZTIgPC0gZGFzeV9jcm9jX3NlcnJhX3BhcmRvIHw+IAogIGdyb3VwX2J5KFNhbXBsZS5MYWJlbCwgeWVhciwgc2Vhc29uKSB8PiAKICBjb3VudChzYW1wbGluZ19kYXkpIHw+IAogIHJlZnJhbWUobl9tYXggPSBtYXgobikpIHw+IAogIHVuZ3JvdXAoKSB8PiAKICBhcnJhbmdlKHllYXIpCgp0ZXN0ZTIKYGBgCgojIyBKdW50YXIgYXMgZHVhcyBkYXRhLmZyYW1lcyBwYXJhIG9idGVyIGFzIGRhdGFzIGNvbSBtYWlvciBuw7ptZXJvIGRlIG9ic2VydmHDp8OjbyBlbSBjYWRhIGFubyBlIGV4Y2x1aXIgZGF0YXMgZGUgYW1vc3RyYWdlbSByZXBpdGlkYXMgbmEgbWVzbWEgZXN0YcOnw6NvIGUgYW5vCgpgYGB7cn0KZGFkb3NfcGFyYV9maWx0cmFyX3Bvcl9kYXRhX3F1YXNlX3NlbV9yZXBldGljYW8gPC0gdGVzdGUxIHw+IAogIHNlbWlfam9pbigKICAgIHRlc3RlMiwgCiAgICBqb2luX2J5KFNhbXBsZS5MYWJlbCwgeWVhciwgc2Vhc29uLCBuID09IG5fbWF4KSwKICApIHw+IAogIGFycmFuZ2Uoc2FtcGxpbmdfZGF5KSB8PgogIGRpc3RpbmN0KHNhbXBsaW5nX2RheSwgeWVhciwgc2Vhc29uKQoKZGFkb3NfcGFyYV9maWx0cmFyX3Bvcl9kYXRhX3F1YXNlX3NlbV9yZXBldGljYW8KYGBgCgojIyMgRGlzdHJpYnVpw6fDo28gZGFzIGRpc3TDom5jaWFzIHBlcnBlbmRpY3VsYXJlcwoKYGBge3J9CmZpbHRyb19kYXRhc19xdWFzZV9zZW1fcmVwZXRpY2FvIDwtIGRhZG9zX3BhcmFfZmlsdHJhcl9wb3JfZGF0YV9xdWFzZV9zZW1fcmVwZXRpY2FvJHNhbXBsaW5nX2RheQogIApkYXN5X2Nyb2Nfc2VycmFfcGFyZG9fcXVhc2Vfc2VtX3JlcGV0aWNhbyA8LSBkYXN5X2Nyb2Nfc2VycmFfcGFyZG8gfD4gCiAgZmlsdGVyKHNhbXBsaW5nX2RheSAlaW4lIGZpbHRyb19kYXRhc19xdWFzZV9zZW1fcmVwZXRpY2FvLAogICAgICAgICBSZWdpb24uTGFiZWwgPT0gIlBhcm5hIGRhIFNlcnJhIGRvIFBhcmRvIikKCmRhc3lfY3JvY19zZXJyYV9wYXJkb19xdWFzZV9zZW1fcmVwZXRpY2FvIHw+IAogIHBsb3Rhcl9kaXN0cmlidWljYW9fZGlzdGFuY2lhX2ludGVyYXRpdm8obGFyZ3VyYV9jYWl4YSA9IDEpCmBgYAoKIyMjIEFqdXN0YW5kbyBtb2RlbG8gZGlzdGFuY2UgY29tIGZ1bsOnw6NvIGRlIGRldGVjw6fDo28gSGFsZi1Ob3JtYWwgZSBkaXN0YW5jaWEgZGUgdHJ1bmNhbWVudG8gMTEKCmBgYHtyfQpkYXN5X2Nyb2Nfc2VycmFfcGFyZG9fcXVhc2Vfc2VtX3JlcGV0aWNhb19obiA8LSBkYXN5X2Nyb2Nfc2VycmFfcGFyZG9fcXVhc2Vfc2VtX3JlcGV0aWNhbyB8PiAKICBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9obih0cnVuY2FtZW50byA9IDExKQpgYGAKCiMjIyBBanVzdGFuZG8gbW9kZWxvIGRpc3RhbmNlIGNvbSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIEhhemFyZC1yYXRlIGUgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIDExCgpgYGB7cn0KZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW9faHIgPC0gZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW8gfD4gCiAgYWp1c3RlX21vZGVsb3NfZGlzdGFuY2VfaHIodHJ1bmNhbWVudG8gPSAxMSkKYGBgCgojIyMgUGxvdCBkb3MgbW9kZWxvcwoKYGBge3J9CmRhc3lfY3JvY19zZXJyYV9wYXJkb19xdWFzZV9zZW1fcmVwZXRpY2FvX2huIHw+IAogIHB1cnJyOjptYXAoXCgueCkgcGxvdCgueCkpIApgYGAKCmBgYHtyfQpkYXN5X2Nyb2Nfc2VycmFfcGFyZG9fcXVhc2Vfc2VtX3JlcGV0aWNhb19ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgojIyMgU2VsZcOnw6NvIGRlIG1vZGVsb3MKCmBgYHtyfQpzdW1tYXJpemVfZHNfbW9kZWxzKAogIGRhc3lfY3JvY19zZXJyYV9wYXJkb19xdWFzZV9zZW1fcmVwZXRpY2FvX2huJGBTZW0gdGVybW9gLAogIGRhc3lfY3JvY19zZXJyYV9wYXJkb19xdWFzZV9zZW1fcmVwZXRpY2FvX2huJENvc3Nlbm8sCiAgZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW9faG4kYEhlcm1pdGUgcG9saW5vbWlhbGAsCiAgZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFNlbSB0ZXJtb2AsCiAgZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW9faHIkQ29zc2VubywKICBkYXN5X2Nyb2Nfc2VycmFfcGFyZG9fcXVhc2Vfc2VtX3JlcGV0aWNhb19ociRgUG9saW5vbWlhbCBzaW1wbGVzYAopCmBgYAoKIyMjIFRlc3RlIGRlIGJvbmRhZGUgZGUgYWp1c3RlCgpgYGB7cn0KZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW9faG4gfD4gCiAgcHVycnI6Om1hcChcKC54KSBnb2ZfZHMobW9kZWwgPSAueCkpCmBgYAoKYGBge3J9CmRhc3lfY3JvY19zZXJyYV9wYXJkb19xdWFzZV9zZW1fcmVwZXRpY2FvX2hyIHw+IAogIHB1cnJyOjptYXAoXCgueCkgZ29mX2RzKG1vZGVsID0gLngpKQpgYGAKCiMjIyBFc3RpbWFuZG8gYSBhYnVuZGFuY2lhCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCBhcmVhIGNvYmVydGEgcGVsbyBlc2ZvcsOnbyBhbW9zdHJhbCwgZXNmb3LDp28gYW1vc3RyYWwgZW0gbWV0cm9zLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzLCBuw7ptZXJvIGRlIHRyYW5zZWN0b3MgKGVhKSwgdGF4YSBkZSBlbmNvbnRybywgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSB0YXhhIGRlIGVuY29udHJvICAKZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW9faG4kQ29zc2VubyRkaHQkaW5kaXZpZHVhbHMkc3VtbWFyeVsxOjldCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgdHJpbGhhcyBvdSBlc3Rhw6fDtWVzIGFtb3N0cmFpcywgZXNmb3LDp28gdG90YWwgZW0gY2FkYSB0cmlsaGEsIGFidW5kw6JuY2lhIGVzdGltYWRhIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCDDoXJlYSB0b3RhbCBhbW9zdHJhZGEKZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW9faG4kQ29zc2VubyRkaHQkaW5kaXZpZHVhbHMkTmhhdC5ieS5zYW1wbGVbMTo4XQpgYGAKCmBgYHtyfQojIHRvdGFsLCBkZW5zaWRhZGUgZXN0aW1hZGEsIGVycm8gcGFkcsOjbyBkYSBkZW5zaWRhZGUgZXN0aW1hZGEsIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgZGVuc2lkYWRlIGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpkYXN5X2Nyb2Nfc2VycmFfcGFyZG9fcXVhc2Vfc2VtX3JlcGV0aWNhb19obiRDb3NzZW5vJGRodCRpbmRpdmlkdWFscyRECgpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIGFyZWEgY29iZXJ0YSBwZWxvIGVzZm9yw6dvIGFtb3N0cmFsLCBlc2ZvcsOnbyBhbW9zdHJhbCBlbSBtZXRyb3MsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMsIG7Dum1lcm8gZGUgdHJhbnNlY3RvcyAoZWEpLCB0YXhhIGRlIGVuY29udHJvLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIHRheGEgZGUgZW5jb250cm8gIApkYXN5X2Nyb2Nfc2VycmFfcGFyZG9fcXVhc2Vfc2VtX3JlcGV0aWNhb19ociRgUG9saW5vbWlhbCBzaW1wbGVzYCRkaHQkaW5kaXZpZHVhbHMkc3VtbWFyeVsxOjldCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgdHJpbGhhcyBvdSBlc3Rhw6fDtWVzIGFtb3N0cmFpcywgZXNmb3LDp28gdG90YWwgZW0gY2FkYSB0cmlsaGEsIGFidW5kw6JuY2lhIGVzdGltYWRhIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCDDoXJlYSB0b3RhbCBhbW9zdHJhZGEKZGFzeV9jcm9jX3NlcnJhX3BhcmRvX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFBvbGlub21pYWwgc2ltcGxlc2AkZGh0JGluZGl2aWR1YWxzJE5oYXQuYnkuc2FtcGxlWzE6OF0KYGBgCgpgYGB7cn0KIyB0b3RhbCwgZGVuc2lkYWRlIGVzdGltYWRhLCBlcnJvIHBhZHLDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpkYXN5X2Nyb2Nfc2VycmFfcGFyZG9fcXVhc2Vfc2VtX3JlcGV0aWNhb19ociRgUG9saW5vbWlhbCBzaW1wbGVzYCRkaHQkaW5kaXZpZHVhbHMkRAoKYGBgCgojIyAqRGFzeXByb2N0YSBjcm9jb25vdGEqIG5hICoqRXNlYyBkYSBUZXJyYSBkbyBNZWlvKioKCiFbRm9udGU6IGJpb2xpYi5jel0oaHR0cHM6Ly93d3cuYmlvbGliLmN6L0lNRy9HQUwvQklHLzIwNTg0OS5qcGcpCgojIyMgQ2FycmVnYXIgZGFkb3MKCmBgYHtyfQpkYXN5X2Nyb2NfdGVycmFfbWVpbyA8LSB0cmFuc2Zvcm1hcl9wYXJhX2Rpc3RhbmNlUl9jb3ZhcmlhdmVpc19zZW1fcmVwZXRpY2FvKCkgfD4gICBmaWx0ZXIoCiAgICBSZWdpb24uTGFiZWwgPT0gIkVzZWMgZGEgVGVycmEgZG8gTWVpbyIsIAogICAgc3BfbmFtZSA9PSAiRGFzeXByb2N0YSBjcm9jb25vdGEiCiAgKSB8PiAKICBkcm9wX25hKGRpc3RhbmNlKQoKZGFzeV9jcm9jX3RlcnJhX21laW8KYGBgCgojIyMgVmVyaWZpY2FyIG8gbsO6bWVybyBkZSBvYnNlcnZhw6fDtWVzIHBvciBkYXRhIGRlIGFtb3N0cmFnZW0KCmBgYHtyfQp0ZXN0ZTEgPC0gZGFzeV9jcm9jX3RlcnJhX21laW8gfD4gCiAgZ3JvdXBfYnkoU2FtcGxlLkxhYmVsLCBzYW1wbGluZ19kYXksIHllYXIsIHNlYXNvbikgfD4gCiAgY291bnQoc2FtcGxpbmdfZGF5KSB8PiAKICB1bmdyb3VwKCkgfD4gCiAgYXJyYW5nZShTYW1wbGUuTGFiZWwsIHNhbXBsaW5nX2RheSkKCnRlc3RlMQpgYGAKCiMjIFZlcmlmaWNhciBhcyBkYXRhcyBjb20gbWFpb3IgbsO6bWVybyBkZSBvYnNlcnZhw6fDtWVzIGVtIGNhZGEgYW5vCnRlbnRhciBnZXJhciB1bWEgbm92YSBjb2x1bmEgdXNhbmRvIHVtYSBjb25kaWNpb25hbCBxdWUgcmVwaXRhIHVtYSDDum5pY2EgZGF0YSBwYXJhIGRhdGFzIHF1ZSBvY29ycmVtIGRlbnRybyBkbyBpbnRlcnZhbG8gYW1vc3RyYWwuIGRlcG9pcyBiYXN0YSBtYW50ZXIgYXMgb2JzZXJ2YcOnw7VlcyDDum5pY2FzIHVzYW5kbyBkaXN0aW5jdCgpCmBgYHtyfQp0ZXN0ZTIgPC0gZGFzeV9jcm9jX3RlcnJhX21laW8gfD4gCiAgZ3JvdXBfYnkoU2FtcGxlLkxhYmVsLCB5ZWFyLCBzZWFzb24pIHw+IAogIGNvdW50KHNhbXBsaW5nX2RheSkgfD4gCiAgcmVmcmFtZShuX21heCA9IG1heChuKSkgfD4gCiAgdW5ncm91cCgpIHw+IAogIGFycmFuZ2UoeWVhcikKCnRlc3RlMgpgYGAKCiMjIEp1bnRhciBhcyBkdWFzIGRhdGEuZnJhbWVzIHBhcmEgb2J0ZXIgYXMgZGF0YXMgY29tIG1haW9yIG7Dum1lcm8gZGUgb2JzZXJ2YcOnw6NvIGVtIGNhZGEgYW5vIGUgZXhjbHVpciBkYXRhcyBkZSBhbW9zdHJhZ2VtIHJlcGl0aWRhcyBuYSBtZXNtYSBlc3Rhw6fDo28gZSBhbm8KCmBgYHtyfQpkYWRvc19wYXJhX2ZpbHRyYXJfcG9yX2RhdGFfcXVhc2Vfc2VtX3JlcGV0aWNhbyA8LSB0ZXN0ZTEgfD4gCiAgc2VtaV9qb2luKAogICAgdGVzdGUyLCAKICAgIGpvaW5fYnkoU2FtcGxlLkxhYmVsLCB5ZWFyLCBzZWFzb24sIG4gPT0gbl9tYXgpLAogICkgfD4gCiAgYXJyYW5nZShzYW1wbGluZ19kYXkpIHw+CiAgZGlzdGluY3Qoc2FtcGxpbmdfZGF5LCB5ZWFyLCBzZWFzb24pCgpkYWRvc19wYXJhX2ZpbHRyYXJfcG9yX2RhdGFfcXVhc2Vfc2VtX3JlcGV0aWNhbwpgYGAKCiMjIyBEaXN0cmlidWnDp8OjbyBkYXMgZGlzdMOibmNpYXMgcGVycGVuZGljdWxhcmVzCgpgYGB7cn0KZmlsdHJvX2RhdGFzX3F1YXNlX3NlbV9yZXBldGljYW8gPC0gZGFkb3NfcGFyYV9maWx0cmFyX3Bvcl9kYXRhX3F1YXNlX3NlbV9yZXBldGljYW8kc2FtcGxpbmdfZGF5CiAgCmRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW8gPC0gZGFzeV9jcm9jX3RlcnJhX21laW8gfD4gCiAgZmlsdGVyKHNhbXBsaW5nX2RheSAlaW4lIGZpbHRyb19kYXRhc19xdWFzZV9zZW1fcmVwZXRpY2FvLAogICAgICAgICBSZWdpb24uTGFiZWwgPT0gIkVzZWMgZGEgVGVycmEgZG8gTWVpbyIpCgpkYXN5X2Nyb2NfdGVycmFfbWVpb19xdWFzZV9zZW1fcmVwZXRpY2FvIHw+IAogIHBsb3Rhcl9kaXN0cmlidWljYW9fZGlzdGFuY2lhX2ludGVyYXRpdm8obGFyZ3VyYV9jYWl4YSA9IDEpCmBgYAoKIyMjIEFqdXN0YW5kbyBtb2RlbG8gZGlzdGFuY2UgY29tIGZ1bsOnw6NvIGRlIGRldGVjw6fDo28gSGFsZi1Ob3JtYWwgZSBkaXN0YW5jaWEgZGUgdHJ1bmNhbWVudG8gMTAKCmBgYHtyfQpkYXN5X2Nyb2NfdGVycmFfbWVpb19xdWFzZV9zZW1fcmVwZXRpY2FvX2huIDwtIGRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW8gfD4gCiAgYWp1c3RlX21vZGVsb3NfZGlzdGFuY2VfaG4odHJ1bmNhbWVudG8gPSAxMCkKYGBgCgojIyMgQWp1c3RhbmRvIG1vZGVsbyBkaXN0YW5jZSBjb20gZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBIYXphcmQtcmF0ZSBlIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byAxMAoKYGBge3J9CmRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW9faHIgPC0gZGFzeV9jcm9jX3RlcnJhX21laW9fcXVhc2Vfc2VtX3JlcGV0aWNhbyB8PiAKICBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9ocih0cnVuY2FtZW50byA9IDEwKQpgYGAKCiMjIyBQbG90IGRvcyBtb2RlbG9zCgpgYGB7cn0KZGFzeV9jcm9jX3RlcnJhX21laW9fcXVhc2Vfc2VtX3JlcGV0aWNhb19obiB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgpgYGB7cn0KZGFzeV9jcm9jX3RlcnJhX21laW9fcXVhc2Vfc2VtX3JlcGV0aWNhb19ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgojIyMgU2VsZcOnw6NvIGRlIG1vZGVsb3MKCmBgYHtyfQpzdW1tYXJpemVfZHNfbW9kZWxzKAogIGRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW9faG4kYFNlbSB0ZXJtb2AsCiAgZGFzeV9jcm9jX3RlcnJhX21laW9fcXVhc2Vfc2VtX3JlcGV0aWNhb19obiRDb3NzZW5vLAogIGRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW9faG4kYEhlcm1pdGUgcG9saW5vbWlhbGAsCiAgZGFzeV9jcm9jX3RlcnJhX21laW9fcXVhc2Vfc2VtX3JlcGV0aWNhb19ociRgU2VtIHRlcm1vYCwKICBkYXN5X2Nyb2NfdGVycmFfbWVpb19xdWFzZV9zZW1fcmVwZXRpY2FvX2hyJENvc3Nlbm8sCiAgZGFzeV9jcm9jX3RlcnJhX21laW9fcXVhc2Vfc2VtX3JlcGV0aWNhb19ociRgUG9saW5vbWlhbCBzaW1wbGVzYAopCmBgYAoKIyMjIFRlc3RlIGRlIGJvbmRhZGUgZGUgYWp1c3RlCgpgYGB7cn0KZGFzeV9jcm9jX3RlcnJhX21laW9fcXVhc2Vfc2VtX3JlcGV0aWNhb19obiB8PiAKICBwdXJycjo6bWFwKFwoLngpIGdvZl9kcyhtb2RlbCA9IC54KSkKYGBgCgpgYGB7cn0KZGFzeV9jcm9jX3RlcnJhX21laW9fcXVhc2Vfc2VtX3JlcGV0aWNhb19ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIGdvZl9kcyhtb2RlbCA9IC54KSkKYGBgCgojIyMgRXN0aW1hbmRvIGEgYWJ1bmRhbmNpYQoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgYXJlYSBjb2JlcnRhIHBlbG8gZXNmb3LDp28gYW1vc3RyYWwsIGVzZm9yw6dvIGFtb3N0cmFsIGVtIG1ldHJvcywgbsO6bWVybyBkZSBkZXRlY8Onw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zIChlYSksIHRheGEgZGUgZW5jb250cm8sIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgdGF4YSBkZSBlbmNvbnRybyAgCmRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW9faG4kYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJHN1bW1hcnlbMTo5XQpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIHRyaWxoYXMgb3UgZXN0YcOnw7VlcyBhbW9zdHJhaXMsIGVzZm9yw6dvIHRvdGFsIGVtIGNhZGEgdHJpbGhhLCBhYnVuZMOibmNpYSBlc3RpbWFkYSBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgbsO6bWVybyBkZSBkZXRlY8Onw7VlcyBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgw6FyZWEgdG90YWwgYW1vc3RyYWRhCmRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW9faG4kQ29zc2VubyRkaHQkaW5kaXZpZHVhbHMkTmhhdC5ieS5zYW1wbGVbMTo4XQpgYGAKCmBgYHtyfQojIHRvdGFsLCBkZW5zaWRhZGUgZXN0aW1hZGEsIGVycm8gcGFkcsOjbyBkYSBkZW5zaWRhZGUgZXN0aW1hZGEsIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgZGVuc2lkYWRlIGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpkYXN5X2Nyb2NfdGVycmFfbWVpb19xdWFzZV9zZW1fcmVwZXRpY2FvX2huJENvc3Nlbm8kZGh0JGluZGl2aWR1YWxzJEQKCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgYXJlYSBjb2JlcnRhIHBlbG8gZXNmb3LDp28gYW1vc3RyYWwsIGVzZm9yw6dvIGFtb3N0cmFsIGVtIG1ldHJvcywgbsO6bWVybyBkZSBkZXRlY8Onw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zIChlYSksIHRheGEgZGUgZW5jb250cm8sIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgdGF4YSBkZSBlbmNvbnRybyAgCmRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJHN1bW1hcnlbMTo5XQpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIHRyaWxoYXMgb3UgZXN0YcOnw7VlcyBhbW9zdHJhaXMsIGVzZm9yw6dvIHRvdGFsIGVtIGNhZGEgdHJpbGhhLCBhYnVuZMOibmNpYSBlc3RpbWFkYSBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgbsO6bWVybyBkZSBkZXRlY8Onw7VlcyBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgw6FyZWEgdG90YWwgYW1vc3RyYWRhCmRhc3lfY3JvY190ZXJyYV9tZWlvX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJE5oYXQuYnkuc2FtcGxlWzE6OF0KYGBgCgpgYGB7cn0KIyB0b3RhbCwgZGVuc2lkYWRlIGVzdGltYWRhLCBlcnJvIHBhZHLDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpkYXN5X2Nyb2NfdGVycmFfbWVpb19xdWFzZV9zZW1fcmVwZXRpY2FvX2hyJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRECgpgYGAKCiMjICpEYXN5cHJvY3RhIGNyb2Nvbm90YSogbmEgKipSZXNleCBSaW96aW5obyBkbyBBbmZyw61zaW8qKgoKIVtGb250ZTogYmlvbGliLmN6XShodHRwczovL3d3dy5iaW9saWIuY3ovSU1HL0dBTC9CSUcvMjA1ODQ5LmpwZykKCiMjIyBDYXJyZWdhciBkYWRvcwoKYGBge3J9CmRhc3lfY3JvY19yaW9fYW5mciA8LSB0cmFuc2Zvcm1hcl9wYXJhX2Rpc3RhbmNlUl9jb3ZhcmlhdmVpc19zZW1fcmVwZXRpY2FvKCkgfD4gICBmaWx0ZXIoCiAgICBSZWdpb24uTGFiZWwgPT0gIlJlc2V4IFJpb3ppbmhvIGRvIEFuZnLDrXNpbyIsIAogICAgc3BfbmFtZSA9PSAiRGFzeXByb2N0YSBjcm9jb25vdGEiCiAgKSB8PiAKICBkcm9wX25hKGRpc3RhbmNlKQoKZGFzeV9jcm9jX3Jpb19hbmZyCmBgYAoKIyMjIFZlcmlmaWNhciBvIG7Dum1lcm8gZGUgb2JzZXJ2YcOnw7VlcyBwb3IgZGF0YSBkZSBhbW9zdHJhZ2VtCgpgYGB7cn0KdGVzdGUxIDwtIGRhc3lfY3JvY19yaW9fYW5mciB8PiAKICBncm91cF9ieShTYW1wbGUuTGFiZWwsIHNhbXBsaW5nX2RheSwgeWVhciwgc2Vhc29uKSB8PiAKICBjb3VudChzYW1wbGluZ19kYXkpIHw+IAogIHVuZ3JvdXAoKSB8PiAKICBhcnJhbmdlKFNhbXBsZS5MYWJlbCwgc2FtcGxpbmdfZGF5KQoKdGVzdGUxCmBgYAoKIyMgVmVyaWZpY2FyIGFzIGRhdGFzIGNvbSBtYWlvciBuw7ptZXJvIGRlIG9ic2VydmHDp8O1ZXMgZW0gY2FkYSBhbm8KdGVudGFyIGdlcmFyIHVtYSBub3ZhIGNvbHVuYSB1c2FuZG8gdW1hIGNvbmRpY2lvbmFsIHF1ZSByZXBpdGEgdW1hIMO6bmljYSBkYXRhIHBhcmEgZGF0YXMgcXVlIG9jb3JyZW0gZGVudHJvIGRvIGludGVydmFsbyBhbW9zdHJhbC4gZGVwb2lzIGJhc3RhIG1hbnRlciBhcyBvYnNlcnZhw6fDtWVzIMO6bmljYXMgdXNhbmRvIGRpc3RpbmN0KCkKYGBge3J9CnRlc3RlMiA8LSBkYXN5X2Nyb2NfcmlvX2FuZnIgfD4gCiAgZ3JvdXBfYnkoU2FtcGxlLkxhYmVsLCB5ZWFyLCBzZWFzb24pIHw+IAogIGNvdW50KHNhbXBsaW5nX2RheSkgfD4gCiAgcmVmcmFtZShuX21heCA9IG1heChuKSkgfD4gCiAgdW5ncm91cCgpIHw+IAogIGFycmFuZ2UoeWVhcikKCnRlc3RlMgpgYGAKCiMjIEp1bnRhciBhcyBkdWFzIGRhdGEuZnJhbWVzIHBhcmEgb2J0ZXIgYXMgZGF0YXMgY29tIG1haW9yIG7Dum1lcm8gZGUgb2JzZXJ2YcOnw6NvIGVtIGNhZGEgYW5vIGUgZXhjbHVpciBkYXRhcyBkZSBhbW9zdHJhZ2VtIHJlcGl0aWRhcyBuYSBtZXNtYSBlc3Rhw6fDo28gZSBhbm8KCmBgYHtyfQpkYWRvc19wYXJhX2ZpbHRyYXJfcG9yX2RhdGFfcXVhc2Vfc2VtX3JlcGV0aWNhbyA8LSB0ZXN0ZTEgfD4gCiAgc2VtaV9qb2luKAogICAgdGVzdGUyLCAKICAgIGpvaW5fYnkoU2FtcGxlLkxhYmVsLCB5ZWFyLCBzZWFzb24sIG4gPT0gbl9tYXgpLAogICkgfD4gCiAgYXJyYW5nZShzYW1wbGluZ19kYXkpIHw+CiAgZGlzdGluY3Qoc2FtcGxpbmdfZGF5LCB5ZWFyLCBzZWFzb24pCgpkYWRvc19wYXJhX2ZpbHRyYXJfcG9yX2RhdGFfcXVhc2Vfc2VtX3JlcGV0aWNhbwpgYGAKCiMjIyBEaXN0cmlidWnDp8OjbyBkYXMgZGlzdMOibmNpYXMgcGVycGVuZGljdWxhcmVzCgpgYGB7cn0KZmlsdHJvX2RhdGFzX3F1YXNlX3NlbV9yZXBldGljYW8gPC0gZGFkb3NfcGFyYV9maWx0cmFyX3Bvcl9kYXRhX3F1YXNlX3NlbV9yZXBldGljYW8kc2FtcGxpbmdfZGF5CiAgCmRhc3lfY3JvY19yaW9fYW5mcl9xdWFzZV9zZW1fcmVwZXRpY2FvIDwtIGRhc3lfY3JvY19yaW9fYW5mciB8PiAKICBmaWx0ZXIoc2FtcGxpbmdfZGF5ICVpbiUgZmlsdHJvX2RhdGFzX3F1YXNlX3NlbV9yZXBldGljYW8sCiAgICAgICAgIFJlZ2lvbi5MYWJlbCA9PSAiUmVzZXggUmlvemluaG8gZG8gQW5mcsOtc2lvIikKCmRhc3lfY3JvY19yaW9fYW5mcl9xdWFzZV9zZW1fcmVwZXRpY2FvIHw+IAogIHBsb3Rhcl9kaXN0cmlidWljYW9fZGlzdGFuY2lhX2ludGVyYXRpdm8obGFyZ3VyYV9jYWl4YSA9IDEpCmBgYAoKIyMjIEFqdXN0YW5kbyBtb2RlbG8gZGlzdGFuY2UgY29tIGZ1bsOnw6NvIGRlIGRldGVjw6fDo28gSGFsZi1Ob3JtYWwgZSBkaXN0YW5jaWEgZGUgdHJ1bmNhbWVudG8gMTEKCmBgYHtyfQpkYXN5X2Nyb2NfcmlvX2FuZnJfcXVhc2Vfc2VtX3JlcGV0aWNhb19obiA8LSBkYXN5X2Nyb2NfcmlvX2FuZnJfcXVhc2Vfc2VtX3JlcGV0aWNhbyB8PiAKICBhanVzdGVfbW9kZWxvc19kaXN0YW5jZV9obih0cnVuY2FtZW50byA9IDExKQpgYGAKCiMjIyBBanVzdGFuZG8gbW9kZWxvIGRpc3RhbmNlIGNvbSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIEhhemFyZC1yYXRlIGUgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIDExCgpgYGB7cn0KZGFzeV9jcm9jX3Jpb19hbmZyX3F1YXNlX3NlbV9yZXBldGljYW9faHIgPC0gZGFzeV9jcm9jX3Jpb19hbmZyX3F1YXNlX3NlbV9yZXBldGljYW8gfD4gCiAgYWp1c3RlX21vZGVsb3NfZGlzdGFuY2VfaHIodHJ1bmNhbWVudG8gPSAxMSkKYGBgCgojIyMgUGxvdCBkb3MgbW9kZWxvcwoKYGBge3J9CmRhc3lfY3JvY19yaW9fYW5mcl9xdWFzZV9zZW1fcmVwZXRpY2FvX2huIHw+IAogIHB1cnJyOjptYXAoXCgueCkgcGxvdCgueCkpIApgYGAKCmBgYHtyfQpkYXN5X2Nyb2NfcmlvX2FuZnJfcXVhc2Vfc2VtX3JlcGV0aWNhb19ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgojIyMgU2VsZcOnw6NvIGRlIG1vZGVsb3MKCmBgYHtyfQpzdW1tYXJpemVfZHNfbW9kZWxzKAogIGRhc3lfY3JvY19yaW9fYW5mcl9xdWFzZV9zZW1fcmVwZXRpY2FvX2huJGBTZW0gdGVybW9gLAogIGRhc3lfY3JvY19yaW9fYW5mcl9xdWFzZV9zZW1fcmVwZXRpY2FvX2huJENvc3Nlbm8sCiAgZGFzeV9jcm9jX3Jpb19hbmZyX3F1YXNlX3NlbV9yZXBldGljYW9faG4kYEhlcm1pdGUgcG9saW5vbWlhbGAsCiAgZGFzeV9jcm9jX3Jpb19hbmZyX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFNlbSB0ZXJtb2AsCiAgZGFzeV9jcm9jX3Jpb19hbmZyX3F1YXNlX3NlbV9yZXBldGljYW9faHIkQ29zc2VubywKICBkYXN5X2Nyb2NfcmlvX2FuZnJfcXVhc2Vfc2VtX3JlcGV0aWNhb19ociRgUG9saW5vbWlhbCBzaW1wbGVzYAopCmBgYAoKIyMjIFRlc3RlIGRlIGJvbmRhZGUgZGUgYWp1c3RlCgpgYGB7cn0KZGFzeV9jcm9jX3Jpb19hbmZyX3F1YXNlX3NlbV9yZXBldGljYW9faG4gfD4gCiAgcHVycnI6Om1hcChcKC54KSBnb2ZfZHMobW9kZWwgPSAueCkpCmBgYAoKYGBge3J9CmRhc3lfY3JvY19yaW9fYW5mcl9xdWFzZV9zZW1fcmVwZXRpY2FvX2hyIHw+IAogIHB1cnJyOjptYXAoXCgueCkgZ29mX2RzKG1vZGVsID0gLngpKQpgYGAKCiMjIyBFc3RpbWFuZG8gYSBhYnVuZGFuY2lhCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCBhcmVhIGNvYmVydGEgcGVsbyBlc2ZvcsOnbyBhbW9zdHJhbCwgZXNmb3LDp28gYW1vc3RyYWwgZW0gbWV0cm9zLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzLCBuw7ptZXJvIGRlIHRyYW5zZWN0b3MgKGVhKSwgdGF4YSBkZSBlbmNvbnRybywgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSB0YXhhIGRlIGVuY29udHJvICAKZGFzeV9jcm9jX3Jpb19hbmZyX3F1YXNlX3NlbV9yZXBldGljYW9faG4kYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJHN1bW1hcnlbMTo5XQpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIHRyaWxoYXMgb3UgZXN0YcOnw7VlcyBhbW9zdHJhaXMsIGVzZm9yw6dvIHRvdGFsIGVtIGNhZGEgdHJpbGhhLCBhYnVuZMOibmNpYSBlc3RpbWFkYSBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgbsO6bWVybyBkZSBkZXRlY8Onw7VlcyBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgw6FyZWEgdG90YWwgYW1vc3RyYWRhCmRhc3lfY3JvY19yaW9fYW5mcl9xdWFzZV9zZW1fcmVwZXRpY2FvX2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyROaGF0LmJ5LnNhbXBsZVsxOjhdCmBgYAoKYGBge3J9CiMgdG90YWwsIGRlbnNpZGFkZSBlc3RpbWFkYSwgZXJybyBwYWRyw6NvIGRhIGRlbnNpZGFkZSBlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZXN0aW1hZGEsIGludGVydmFsbyBkZSBjb25maWFuw6dhIGluZmVyaW9yIGUgc3VwZXJpb3IgZG8gY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbywgZ3J1YXMgZGUgbGliZXJkYWRlCmRhc3lfY3JvY19yaW9fYW5mcl9xdWFzZV9zZW1fcmVwZXRpY2FvX2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRECgpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIGFyZWEgY29iZXJ0YSBwZWxvIGVzZm9yw6dvIGFtb3N0cmFsLCBlc2ZvcsOnbyBhbW9zdHJhbCBlbSBtZXRyb3MsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMsIG7Dum1lcm8gZGUgdHJhbnNlY3RvcyAoZWEpLCB0YXhhIGRlIGVuY29udHJvLCBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGRhIHRheGEgZGUgZW5jb250cm8gIApkYXN5X2Nyb2NfcmlvX2FuZnJfcXVhc2Vfc2VtX3JlcGV0aWNhb19ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkc3VtbWFyeVsxOjldCmBgYAoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgdHJpbGhhcyBvdSBlc3Rhw6fDtWVzIGFtb3N0cmFpcywgZXNmb3LDp28gdG90YWwgZW0gY2FkYSB0cmlsaGEsIGFidW5kw6JuY2lhIGVzdGltYWRhIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzIGVtIGNhZGEgZXN0YcOnw6NvIGFtb3N0cmFsLCDDoXJlYSB0b3RhbCBhbW9zdHJhZGEKZGFzeV9jcm9jX3Jpb19hbmZyX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJE5oYXQuYnkuc2FtcGxlWzE6OF0KYGBgCgpgYGB7cn0KIyB0b3RhbCwgZGVuc2lkYWRlIGVzdGltYWRhLCBlcnJvIHBhZHLDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSBkZW5zaWRhZGUgZGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpkYXN5X2Nyb2NfcmlvX2FuZnJfcXVhc2Vfc2VtX3JlcGV0aWNhb19ociRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkRAoKYGBgCgojIyAqRGFzeXByb2N0YSBjcm9jb25vdGEqIG5hICoqUmVzZXggVGFwYWrDs3MgQXJhcGl1bnMqKiAtIGVzdHJhdGlmaWNhZG8gcG9yIGFubwoKIVtGb250ZTogYmlvbGliLmN6XShodHRwczovL3d3dy5iaW9saWIuY3ovSU1HL0dBTC9CSUcvMjA1ODQ5LmpwZykKCiMjIyBDYXJyZWdhciBkYWRvcwoKYGBge3J9CmRhc3lfY3JvY190YXBfYXJhcCA8LSB0cmFuc2Zvcm1hcl9wYXJhX2Rpc3RhbmNlUl9jb3ZhcmlhdmVpc19zZW1fcmVwZXRpY2FvKCkgfD4gICBmaWx0ZXIoCiAgICBSZWdpb24uTGFiZWwgPT0gIlJlc2V4IFRhcGFqw7NzIEFyYXBpdW5zIiwgCiAgICBzcF9uYW1lID09ICJEYXN5cHJvY3RhIGNyb2Nvbm90YSIKICApIHw+IAogIGRyb3BfbmEoZGlzdGFuY2UpCgpkYXN5X2Nyb2NfdGFwX2FyYXAKYGBgCgojIyMgVmVyaWZpY2FyIG8gbsO6bWVybyBkZSBvYnNlcnZhw6fDtWVzIHBvciBkYXRhIGRlIGFtb3N0cmFnZW0KCmBgYHtyfQp0ZXN0ZTEgPC0gZGFzeV9jcm9jX3RhcF9hcmFwIHw+IAogIGdyb3VwX2J5KFNhbXBsZS5MYWJlbCwgc2FtcGxpbmdfZGF5LCB5ZWFyLCBzZWFzb24pIHw+IAogIGNvdW50KHNhbXBsaW5nX2RheSkgfD4gCiAgdW5ncm91cCgpIHw+IAogIGFycmFuZ2UoU2FtcGxlLkxhYmVsLCBzYW1wbGluZ19kYXkpCgp0ZXN0ZTEKYGBgCgojIyBWZXJpZmljYXIgYXMgZGF0YXMgY29tIG1haW9yIG7Dum1lcm8gZGUgb2JzZXJ2YcOnw7VlcyBlbSBjYWRhIGFubwp0ZW50YXIgZ2VyYXIgdW1hIG5vdmEgY29sdW5hIHVzYW5kbyB1bWEgY29uZGljaW9uYWwgcXVlIHJlcGl0YSB1bWEgw7puaWNhIGRhdGEgcGFyYSBkYXRhcyBxdWUgb2NvcnJlbSBkZW50cm8gZG8gaW50ZXJ2YWxvIGFtb3N0cmFsLiBkZXBvaXMgYmFzdGEgbWFudGVyIGFzIG9ic2VydmHDp8O1ZXMgw7puaWNhcyB1c2FuZG8gZGlzdGluY3QoKQpgYGB7cn0KdGVzdGUyIDwtIGRhc3lfY3JvY190YXBfYXJhcCB8PiAKICBncm91cF9ieShTYW1wbGUuTGFiZWwsIHllYXIsIHNlYXNvbikgfD4gCiAgY291bnQoc2FtcGxpbmdfZGF5KSB8PiAKICByZWZyYW1lKG5fbWF4ID0gbWF4KG4pKSB8PiAKICB1bmdyb3VwKCkgfD4gCiAgYXJyYW5nZSh5ZWFyKQoKdGVzdGUyCmBgYAoKIyMgSnVudGFyIGFzIGR1YXMgZGF0YS5mcmFtZXMgcGFyYSBvYnRlciBhcyBkYXRhcyBjb20gbWFpb3IgbsO6bWVybyBkZSBvYnNlcnZhw6fDo28gZW0gY2FkYSBhbm8gZSBleGNsdWlyIGRhdGFzIGRlIGFtb3N0cmFnZW0gcmVwaXRpZGFzIG5hIG1lc21hIGVzdGHDp8OjbyBlIGFubwoKYGBge3J9CmRhZG9zX3BhcmFfZmlsdHJhcl9wb3JfZGF0YV9xdWFzZV9zZW1fcmVwZXRpY2FvIDwtIHRlc3RlMSB8PiAKICBzZW1pX2pvaW4oCiAgICB0ZXN0ZTIsIAogICAgam9pbl9ieShTYW1wbGUuTGFiZWwsIHllYXIsIHNlYXNvbiwgbiA9PSBuX21heCksCiAgKSB8PiAKICBhcnJhbmdlKHNhbXBsaW5nX2RheSkgfD4KICBkaXN0aW5jdChzYW1wbGluZ19kYXksIHllYXIsIHNlYXNvbikKCmRhZG9zX3BhcmFfZmlsdHJhcl9wb3JfZGF0YV9xdWFzZV9zZW1fcmVwZXRpY2FvCmBgYAoKIyMjIERpc3RyaWJ1acOnw6NvIGRhcyBkaXN0w6JuY2lhcyBwZXJwZW5kaWN1bGFyZXMKCmBgYHtyfQpmaWx0cm9fZGF0YXNfcXVhc2Vfc2VtX3JlcGV0aWNhbyA8LSBkYWRvc19wYXJhX2ZpbHRyYXJfcG9yX2RhdGFfcXVhc2Vfc2VtX3JlcGV0aWNhbyRzYW1wbGluZ19kYXkKICAKZGFzeV9jcm9jX3RhcF9hcmFwX3F1YXNlX3NlbV9yZXBldGljYW8gPC0gZGFzeV9jcm9jX3RhcF9hcmFwIHw+IAogIGZpbHRlcihzYW1wbGluZ19kYXkgJWluJSBmaWx0cm9fZGF0YXNfcXVhc2Vfc2VtX3JlcGV0aWNhbywKICAgICAgICAgUmVnaW9uLkxhYmVsID09ICJSZXNleCBUYXBhasOzcyBBcmFwaXVucyIpCgpkYXN5X2Nyb2NfdGFwX2FyYXBfcXVhc2Vfc2VtX3JlcGV0aWNhbyB8PiAKICBwbG90YXJfZGlzdHJpYnVpY2FvX2Rpc3RhbmNpYV9pbnRlcmF0aXZvKGxhcmd1cmFfY2FpeGEgPSAxKQpgYGAKCiMjIyBBanVzdGFuZG8gbW9kZWxvIGRpc3RhbmNlIGNvbSBmdW7Dp8OjbyBkZSBkZXRlY8Onw6NvIEhhbGYtTm9ybWFsIGUgZGlzdGFuY2lhIGRlIHRydW5jYW1lbnRvIDExCgpgYGB7cn0KZGFzeV9jcm9jX3RhcF9hcmFwX3F1YXNlX3NlbV9yZXBldGljYW9faG4gPC0gZGFzeV9jcm9jX3RhcF9hcmFwX3F1YXNlX3NlbV9yZXBldGljYW8gfD4gCiAgYWp1c3RlX21vZGVsb3NfZGlzdGFuY2VfaG4odHJ1bmNhbWVudG8gPSAxMSkKYGBgCgojIyMgQWp1c3RhbmRvIG1vZGVsbyBkaXN0YW5jZSBjb20gZnVuw6fDo28gZGUgZGV0ZWPDp8OjbyBIYXphcmQtcmF0ZSBlIGRpc3RhbmNpYSBkZSB0cnVuY2FtZW50byAxMQoKYGBge3J9CmRhc3lfY3JvY190YXBfYXJhcF9xdWFzZV9zZW1fcmVwZXRpY2FvX2hyIDwtIGRhc3lfY3JvY190YXBfYXJhcF9xdWFzZV9zZW1fcmVwZXRpY2FvIHw+IAogIGFqdXN0ZV9tb2RlbG9zX2Rpc3RhbmNlX2hyKHRydW5jYW1lbnRvID0gMTEpCmBgYAoKIyMjIFBsb3QgZG9zIG1vZGVsb3MKCmBgYHtyfQpkYXN5X2Nyb2NfdGFwX2FyYXBfcXVhc2Vfc2VtX3JlcGV0aWNhb19obiB8PiAKICBwdXJycjo6bWFwKFwoLngpIHBsb3QoLngpKSAKYGBgCgpgYGB7cn0KZGFzeV9jcm9jX3RhcF9hcmFwX3F1YXNlX3NlbV9yZXBldGljYW9faHIgfD4gCiAgcHVycnI6Om1hcChcKC54KSBwbG90KC54KSkgCmBgYAoKIyMjIFNlbGXDp8OjbyBkZSBtb2RlbG9zCgpgYGB7cn0Kc3VtbWFyaXplX2RzX21vZGVscygKICBkYXN5X2Nyb2NfdGFwX2FyYXBfcXVhc2Vfc2VtX3JlcGV0aWNhb19obiRgU2VtIHRlcm1vYCwKICBkYXN5X2Nyb2NfdGFwX2FyYXBfcXVhc2Vfc2VtX3JlcGV0aWNhb19obiRDb3NzZW5vLAogIGRhc3lfY3JvY190YXBfYXJhcF9xdWFzZV9zZW1fcmVwZXRpY2FvX2huJGBIZXJtaXRlIHBvbGlub21pYWxgLAogIGRhc3lfY3JvY190YXBfYXJhcF9xdWFzZV9zZW1fcmVwZXRpY2FvX2hyJGBTZW0gdGVybW9gLAogIGRhc3lfY3JvY190YXBfYXJhcF9xdWFzZV9zZW1fcmVwZXRpY2FvX2hyJENvc3Nlbm8sCiAgZGFzeV9jcm9jX3RhcF9hcmFwX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFBvbGlub21pYWwgc2ltcGxlc2AKKQpgYGAKCiMjIyBUZXN0ZSBkZSBib25kYWRlIGRlIGFqdXN0ZQoKYGBge3J9CmRhc3lfY3JvY190YXBfYXJhcF9xdWFzZV9zZW1fcmVwZXRpY2FvX2huIHw+IAogIHB1cnJyOjptYXAoXCgueCkgZ29mX2RzKG1vZGVsID0gLngpKQpgYGAKCmBgYHtyfQpkYXN5X2Nyb2NfdGFwX2FyYXBfcXVhc2Vfc2VtX3JlcGV0aWNhb19ociB8PiAKICBwdXJycjo6bWFwKFwoLngpIGdvZl9kcyhtb2RlbCA9IC54KSkKYGBgCgojIyMgRXN0aW1hbmRvIGEgYWJ1bmRhbmNpYQoKYGBge3J9CiMgw6FyZWEgZGUgZXN0dWRvLCB0YW1hbmhvIGRhIMOhcmVhIGRlIGVzdHVkbywgYXJlYSBjb2JlcnRhIHBlbG8gZXNmb3LDp28gYW1vc3RyYWwsIGVzZm9yw6dvIGFtb3N0cmFsIGVtIG1ldHJvcywgbsO6bWVybyBkZSBkZXRlY8Onw7VlcywgbsO6bWVybyBkZSB0cmFuc2VjdG9zIChlYSksIHRheGEgZGUgZW5jb250cm8sIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgdGF4YSBkZSBlbmNvbnRybyAgCmRhc3lfY3JvY190YXBfYXJhcF9xdWFzZV9zZW1fcmVwZXRpY2FvX2huJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyRzdW1tYXJ5WzE6OV0KYGBgCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCB0cmlsaGFzIG91IGVzdGHDp8O1ZXMgYW1vc3RyYWlzLCBlc2ZvcsOnbyB0b3RhbCBlbSBjYWRhIHRyaWxoYSwgYWJ1bmTDom5jaWEgZXN0aW1hZGEgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIG7Dum1lcm8gZGUgZGV0ZWPDp8O1ZXMgZW0gY2FkYSBlc3Rhw6fDo28gYW1vc3RyYWwsIMOhcmVhIHRvdGFsIGFtb3N0cmFkYQpkYXN5X2Nyb2NfdGFwX2FyYXBfcXVhc2Vfc2VtX3JlcGV0aWNhb19obiRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkTmhhdC5ieS5zYW1wbGVbMTo4XQpgYGAKCmBgYHtyfQojIHRvdGFsLCBkZW5zaWRhZGUgZXN0aW1hZGEsIGVycm8gcGFkcsOjbyBkYSBkZW5zaWRhZGUgZXN0aW1hZGEsIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgZGVuc2lkYWRlIGVzdGltYWRhLCBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBpbmZlcmlvciBlIHN1cGVyaW9yIGRvIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28sIGdydWFzIGRlIGxpYmVyZGFkZQpkYXN5X2Nyb2NfdGFwX2FyYXBfcXVhc2Vfc2VtX3JlcGV0aWNhb19obiRgU2VtIHRlcm1vYCRkaHQkaW5kaXZpZHVhbHMkRAoKYGBgCgpgYGB7cn0KIyDDoXJlYSBkZSBlc3R1ZG8sIHRhbWFuaG8gZGEgw6FyZWEgZGUgZXN0dWRvLCBhcmVhIGNvYmVydGEgcGVsbyBlc2ZvcsOnbyBhbW9zdHJhbCwgZXNmb3LDp28gYW1vc3RyYWwgZW0gbWV0cm9zLCBuw7ptZXJvIGRlIGRldGVjw6fDtWVzLCBuw7ptZXJvIGRlIHRyYW5zZWN0b3MgKGVhKSwgdGF4YSBkZSBlbmNvbnRybywgY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBkYSB0YXhhIGRlIGVuY29udHJvICAKZGFzeV9jcm9jX3RhcF9hcmFwX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJHN1bW1hcnlbMTo5XQpgYGAKCmBgYHtyfQojIMOhcmVhIGRlIGVzdHVkbywgdGFtYW5obyBkYSDDoXJlYSBkZSBlc3R1ZG8sIHRyaWxoYXMgb3UgZXN0YcOnw7VlcyBhbW9zdHJhaXMsIGVzZm9yw6dvIHRvdGFsIGVtIGNhZGEgdHJpbGhhLCBhYnVuZMOibmNpYSBlc3RpbWFkYSBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgbsO6bWVybyBkZSBkZXRlY8Onw7VlcyBlbSBjYWRhIGVzdGHDp8OjbyBhbW9zdHJhbCwgw6FyZWEgdG90YWwgYW1vc3RyYWRhCmRhc3lfY3JvY190YXBfYXJhcF9xdWFzZV9zZW1fcmVwZXRpY2FvX2hyJGBTZW0gdGVybW9gJGRodCRpbmRpdmlkdWFscyROaGF0LmJ5LnNhbXBsZVsxOjhdCmBgYAoKYGBge3J9CiMgdG90YWwsIGRlbnNpZGFkZSBlc3RpbWFkYSwgZXJybyBwYWRyw6NvIGRhIGRlbnNpZGFkZSBkZXN0aW1hZGEsIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gZGEgZGVuc2lkYWRlIGRlc3RpbWFkYSwgaW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EgaW5mZXJpb3IgZSBzdXBlcmlvciBkbyBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvLCBncnVhcyBkZSBsaWJlcmRhZGUKZGFzeV9jcm9jX3RhcF9hcmFwX3F1YXNlX3NlbV9yZXBldGljYW9faHIkYFNlbSB0ZXJtb2AkZGh0JGluZGl2aWR1YWxzJEQKCmBgYAo=